From aa35045840b78d3f48212db45da59a2e5c69b223 Mon Sep 17 00:00:00 2001 From: saurabhb17 Date: Wed, 26 Feb 2020 15:57:49 +0530 Subject: Added main execs --- eeschema/CMakeLists.txt | 383 ++ eeschema/Info.plist | 35 + eeschema/annotate.cpp | 200 + eeschema/backanno.cpp | 264 ++ eeschema/block.cpp | 538 +++ eeschema/block_libedit.cpp | 355 ++ eeschema/bus-wire-junction.cpp | 505 +++ eeschema/busentry.cpp | 83 + eeschema/class_drc_erc_item.cpp | 68 + eeschema/class_libentry.cpp | 1898 ++++++++ eeschema/class_libentry.h | 773 ++++ eeschema/class_library.cpp | 1208 +++++ eeschema/class_library.h | 670 +++ eeschema/class_netlist_object.cpp | 423 ++ eeschema/class_netlist_object.h | 483 ++ eeschema/class_sch_screen.h | 599 +++ eeschema/cmp_library.keywords | 33 + eeschema/cmp_library_lexer.cpp | 6 + eeschema/component_references_lister.cpp | 788 ++++ eeschema/component_tree_search_container.cpp | 443 ++ eeschema/component_tree_search_container.h | 145 + eeschema/controle.cpp | 326 ++ eeschema/cross-probing.cpp | 214 + eeschema/dialog_erc_listbox.h | 120 + eeschema/dialogs/dialog_annotate.cpp | 320 ++ eeschema/dialogs/dialog_annotate_base.cpp | 245 ++ eeschema/dialogs/dialog_annotate_base.fbp | 2636 +++++++++++ eeschema/dialogs/dialog_annotate_base.h | 94 + eeschema/dialogs/dialog_bom.cpp | 621 +++ eeschema/dialogs/dialog_bom_base.cpp | 118 + eeschema/dialogs/dialog_bom_base.fbp | 1445 ++++++ eeschema/dialogs/dialog_bom_base.h | 98 + eeschema/dialogs/dialog_bom_cfg.keywords | 4 + eeschema/dialogs/dialog_bom_help.html | 282 ++ eeschema/dialogs/dialog_choose_component.cpp | 409 ++ eeschema/dialogs/dialog_choose_component.h | 92 + eeschema/dialogs/dialog_choose_component_base.cpp | 93 + eeschema/dialogs/dialog_choose_component_base.fbp | 594 +++ eeschema/dialogs/dialog_choose_component_base.h | 69 + eeschema/dialogs/dialog_color_config.cpp | 296 ++ eeschema/dialogs/dialog_color_config.h | 58 + eeschema/dialogs/dialog_color_config_base.cpp | 48 + eeschema/dialogs/dialog_color_config_base.fbp | 217 + eeschema/dialogs/dialog_color_config_base.h | 52 + eeschema/dialogs/dialog_edit_component_in_lib.cpp | 579 +++ eeschema/dialogs/dialog_edit_component_in_lib.h | 70 + .../dialogs/dialog_edit_component_in_lib_base.cpp | 294 ++ .../dialogs/dialog_edit_component_in_lib_base.fbp | 3354 ++++++++++++++ .../dialogs/dialog_edit_component_in_lib_base.h | 119 + .../dialogs/dialog_edit_component_in_schematic.cpp | 1107 +++++ .../dialog_edit_component_in_schematic_fbp.cpp | 324 ++ .../dialog_edit_component_in_schematic_fbp.fbp | 3532 +++++++++++++++ .../dialog_edit_component_in_schematic_fbp.h | 109 + eeschema/dialogs/dialog_edit_label.cpp | 326 ++ eeschema/dialogs/dialog_edit_label_base.cpp | 118 + eeschema/dialogs/dialog_edit_label_base.fbp | 968 ++++ eeschema/dialogs/dialog_edit_label_base.h | 75 + .../dialogs/dialog_edit_libentry_fields_in_lib.cpp | 796 ++++ .../dialog_edit_libentry_fields_in_lib_base.cpp | 229 + .../dialog_edit_libentry_fields_in_lib_base.fbp | 2326 ++++++++++ .../dialog_edit_libentry_fields_in_lib_base.h | 92 + eeschema/dialogs/dialog_edit_one_field.cpp | 278 ++ eeschema/dialogs/dialog_edit_one_field.h | 159 + eeschema/dialogs/dialog_eeschema_config.cpp | 490 +++ eeschema/dialogs/dialog_eeschema_config_fbp.cpp | 175 + eeschema/dialogs/dialog_eeschema_config_fbp.fbp | 1588 +++++++ eeschema/dialogs/dialog_eeschema_config_fbp.h | 89 + eeschema/dialogs/dialog_eeschema_options.cpp | 371 ++ eeschema/dialogs/dialog_eeschema_options.h | 479 ++ eeschema/dialogs/dialog_eeschema_options_base.cpp | 303 ++ eeschema/dialogs/dialog_eeschema_options_base.fbp | 4612 ++++++++++++++++++++ eeschema/dialogs/dialog_eeschema_options_base.h | 145 + eeschema/dialogs/dialog_erc.cpp | 579 +++ eeschema/dialogs/dialog_erc.h | 92 + eeschema/dialogs/dialog_erc_base.cpp | 152 + eeschema/dialogs/dialog_erc_base.fbp | 1799 ++++++++ eeschema/dialogs/dialog_erc_base.h | 88 + eeschema/dialogs/dialog_lib_edit_draw_item.cpp | 131 + eeschema/dialogs/dialog_lib_edit_draw_item.fbp | 1205 +++++ eeschema/dialogs/dialog_lib_edit_draw_item.h | 67 + .../dialogs/dialog_lib_edit_draw_item_base.cpp | 140 + eeschema/dialogs/dialog_lib_edit_draw_item_base.h | 67 + eeschema/dialogs/dialog_lib_edit_pin.cpp | 193 + eeschema/dialogs/dialog_lib_edit_pin.h | 146 + eeschema/dialogs/dialog_lib_edit_pin_base.cpp | 224 + eeschema/dialogs/dialog_lib_edit_pin_base.fbp | 2299 ++++++++++ eeschema/dialogs/dialog_lib_edit_pin_base.h | 104 + eeschema/dialogs/dialog_lib_edit_pin_table.cpp | 584 +++ eeschema/dialogs/dialog_lib_edit_pin_table.h | 18 + .../dialogs/dialog_lib_edit_pin_table_base.cpp | 46 + .../dialogs/dialog_lib_edit_pin_table_base.fbp | 193 + eeschema/dialogs/dialog_lib_edit_pin_table_base.h | 53 + eeschema/dialogs/dialog_lib_edit_text.cpp | 222 + eeschema/dialogs/dialog_lib_edit_text.h | 54 + eeschema/dialogs/dialog_lib_edit_text_base.cpp | 150 + eeschema/dialogs/dialog_lib_edit_text_base.fbp | 1427 ++++++ eeschema/dialogs/dialog_lib_edit_text_base.h | 74 + eeschema/dialogs/dialog_lib_new_component.cpp | 45 + eeschema/dialogs/dialog_lib_new_component.fbp | 1597 +++++++ eeschema/dialogs/dialog_lib_new_component.h | 97 + eeschema/dialogs/dialog_lib_new_component_base.cpp | 146 + eeschema/dialogs/dialog_lib_new_component_base.h | 67 + eeschema/dialogs/dialog_libedit_options.cpp | 69 + eeschema/dialogs/dialog_libedit_options.h | 93 + eeschema/dialogs/dialog_libedit_options_base.cpp | 195 + eeschema/dialogs/dialog_libedit_options_base.fbp | 2904 ++++++++++++ eeschema/dialogs/dialog_libedit_options_base.h | 85 + eeschema/dialogs/dialog_netlist.cpp | 886 ++++ eeschema/dialogs/dialog_netlist_base.cpp | 151 + eeschema/dialogs/dialog_netlist_base.fbp | 1624 +++++++ eeschema/dialogs/dialog_netlist_base.h | 124 + eeschema/dialogs/dialog_plot_schematic.cpp | 357 ++ eeschema/dialogs/dialog_plot_schematic.h | 157 + eeschema/dialogs/dialog_plot_schematic_base.cpp | 184 + eeschema/dialogs/dialog_plot_schematic_base.fbp | 1852 ++++++++ eeschema/dialogs/dialog_plot_schematic_base.h | 91 + eeschema/dialogs/dialog_print_using_printer.cpp | 487 +++ .../dialogs/dialog_print_using_printer_base.cpp | 80 + .../dialogs/dialog_print_using_printer_base.fbp | 732 ++++ eeschema/dialogs/dialog_print_using_printer_base.h | 61 + eeschema/dialogs/dialog_rescue_each.cpp | 316 ++ eeschema/dialogs/dialog_rescue_each_base.cpp | 127 + eeschema/dialogs/dialog_rescue_each_base.fbp | 978 +++++ eeschema/dialogs/dialog_rescue_each_base.h | 70 + eeschema/dialogs/dialog_sch_edit_sheet_pin.cpp | 60 + eeschema/dialogs/dialog_sch_edit_sheet_pin.h | 59 + .../dialogs/dialog_sch_edit_sheet_pin_base.cpp | 102 + .../dialogs/dialog_sch_edit_sheet_pin_base.fbp | 1043 +++++ eeschema/dialogs/dialog_sch_edit_sheet_pin_base.h | 61 + eeschema/dialogs/dialog_sch_sheet_props.cpp | 61 + eeschema/dialogs/dialog_sch_sheet_props.fbp | 1503 +++++++ eeschema/dialogs/dialog_sch_sheet_props.h | 80 + eeschema/dialogs/dialog_sch_sheet_props_base.cpp | 131 + eeschema/dialogs/dialog_sch_sheet_props_base.h | 65 + eeschema/dialogs/dialog_schematic_find.cpp | 284 ++ eeschema/dialogs/dialog_schematic_find.h | 201 + eeschema/dialogs/dialog_schematic_find_base.cpp | 169 + eeschema/dialogs/dialog_schematic_find_base.fbp | 1901 ++++++++ eeschema/dialogs/dialog_schematic_find_base.h | 81 + eeschema/edit_bitmap.cpp | 199 + eeschema/edit_component_in_schematic.cpp | 117 + eeschema/edit_label.cpp | 320 ++ eeschema/eeredraw.cpp | 86 + eeschema/eeschema.cpp | 242 + eeschema/eeschema.icns | Bin 0 -> 178654 bytes eeschema/eeschema.rc | 3 + eeschema/eeschema_config.cpp | 810 ++++ eeschema/eeschema_config.h | 13 + eeschema/eeschema_doc.icns | Bin 0 -> 144703 bytes eeschema/eeschema_id.h | 252 ++ eeschema/erc.cpp | 617 +++ eeschema/erc.h | 127 + eeschema/events_called_functions_for_edit.cpp | 79 + eeschema/files-io.cpp | 547 +++ eeschema/find.cpp | 515 +++ eeschema/general.h | 150 + eeschema/getpart.cpp | 402 ++ eeschema/help_common_strings.h | 90 + eeschema/hierarch.cpp | 313 ++ eeschema/hotkeys.cpp | 876 ++++ eeschema/hotkeys.h | 96 + eeschema/invoke_sch_dialog.h | 97 + eeschema/lib_arc.cpp | 825 ++++ eeschema/lib_arc.h | 161 + eeschema/lib_bezier.cpp | 421 ++ eeschema/lib_bezier.h | 119 + eeschema/lib_circle.cpp | 356 ++ eeschema/lib_circle.h | 121 + eeschema/lib_collectors.cpp | 131 + eeschema/lib_collectors.h | 135 + eeschema/lib_draw_item.cpp | 160 + eeschema/lib_draw_item.h | 448 ++ eeschema/lib_export.cpp | 191 + eeschema/lib_field.cpp | 771 ++++ eeschema/lib_field.h | 277 ++ eeschema/lib_pin.cpp | 2314 ++++++++++ eeschema/lib_pin.h | 561 +++ eeschema/lib_polyline.cpp | 562 +++ eeschema/lib_polyline.h | 133 + eeschema/lib_rectangle.cpp | 434 ++ eeschema/lib_rectangle.h | 126 + eeschema/lib_text.cpp | 559 +++ eeschema/lib_text.h | 152 + eeschema/libarch.cpp | 119 + eeschema/libedit.cpp | 742 ++++ eeschema/libedit_onleftclick.cpp | 213 + eeschema/libedit_onrightclick.cpp | 348 ++ eeschema/libedit_plot_component.cpp | 214 + eeschema/libedit_undo_redo.cpp | 137 + eeschema/libeditframe.cpp | 1375 ++++++ eeschema/libeditframe.h | 678 +++ eeschema/libfield.cpp | 161 + eeschema/load_one_schematic_file.cpp | 413 ++ eeschema/menubar.cpp | 521 +++ eeschema/menubar_libedit.cpp | 297 ++ eeschema/netform.cpp | 149 + eeschema/netlist.cpp | 971 +++++ eeschema/netlist.h | 62 + eeschema/netlist_exporters/netlist_exporter.cpp | 364 ++ eeschema/netlist_exporters/netlist_exporter.h | 235 + .../netlist_exporters/netlist_exporter_cadstar.cpp | 204 + .../netlist_exporters/netlist_exporter_cadstar.h | 62 + .../netlist_exporters/netlist_exporter_generic.cpp | 580 +++ .../netlist_exporters/netlist_exporter_generic.h | 135 + .../netlist_exporters/netlist_exporter_kicad.cpp | 77 + .../netlist_exporters/netlist_exporter_kicad.h | 63 + .../netlist_exporter_orcadpcb2.cpp | 145 + .../netlist_exporters/netlist_exporter_orcadpcb2.h | 46 + .../netlist_exporters/netlist_exporter_pspice.cpp | 358 ++ .../netlist_exporters/netlist_exporter_pspice.h | 50 + eeschema/onleftclick.cpp | 407 ++ eeschema/onrightclick.cpp | 927 ++++ eeschema/operations_on_items_lists.cpp | 264 ++ eeschema/pinedit.cpp | 786 ++++ eeschema/plot_schematic_DXF.cpp | 166 + eeschema/plot_schematic_HPGL.cpp | 260 ++ eeschema/plot_schematic_PDF.cpp | 209 + eeschema/plot_schematic_PS.cpp | 191 + eeschema/plot_schematic_SVG.cpp | 205 + eeschema/plugins/CMakeLists.txt | 30 + eeschema/plugins/python_scripts/README-bom.txt | 38 + .../python_scripts/bom_csv_grouped_by_value.py | 167 + .../bom_csv_grouped_by_value_with_fp.py | 65 + .../python_scripts/bom_csv_sorted_by_ref.py | 62 + .../python_scripts/bom_html_grouped_by_value.py | 98 + .../bom_html_with_advanced_grouping.py | 132 + .../plugins/python_scripts/bom_sorted_by_ref.py | 61 + .../plugins/python_scripts/kicad_netlist_reader.py | 764 ++++ eeschema/plugins/python_scripts/round_robin.py | 28 + .../plugins/python_scripts/round_value_robin.py | 74 + eeschema/plugins/xsl_scripts/bom2csv.xsl | 99 + eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl | 104 + .../xsl_scripts/bom_with_title_block_2_csv.xsl | 167 + .../plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl | 210 + .../xsl_scripts/netlist_form_cadstar-RINF.xsl | 131 + .../plugins/xsl_scripts/netlist_form_cadstar.xsl | 123 + .../plugins/xsl_scripts/netlist_form_pads-pcb.xsl | 69 + eeschema/project_rescue.cpp | 569 +++ eeschema/project_rescue.h | 198 + eeschema/protos.h | 58 + eeschema/sch_base_frame.cpp | 203 + eeschema/sch_base_frame.h | 213 + eeschema/sch_bitmap.cpp | 309 ++ eeschema/sch_bitmap.h | 149 + eeschema/sch_bus_entry.cpp | 403 ++ eeschema/sch_bus_entry.h | 185 + eeschema/sch_collectors.cpp | 571 +++ eeschema/sch_collectors.h | 408 ++ eeschema/sch_component.cpp | 2048 +++++++++ eeschema/sch_component.h | 496 +++ eeschema/sch_field.cpp | 589 +++ eeschema/sch_field.h | 202 + eeschema/sch_item_struct.cpp | 151 + eeschema/sch_item_struct.h | 432 ++ eeschema/sch_junction.cpp | 235 + eeschema/sch_junction.h | 113 + eeschema/sch_line.cpp | 611 +++ eeschema/sch_line.h | 157 + eeschema/sch_marker.cpp | 186 + eeschema/sch_marker.h | 117 + eeschema/sch_no_connect.cpp | 252 ++ eeschema/sch_no_connect.h | 115 + eeschema/sch_reference_list.h | 469 ++ eeschema/sch_screen.cpp | 1563 +++++++ eeschema/sch_sheet.cpp | 1236 ++++++ eeschema/sch_sheet.h | 600 +++ eeschema/sch_sheet_path.cpp | 924 ++++ eeschema/sch_sheet_path.h | 571 +++ eeschema/sch_sheet_pin.cpp | 526 +++ eeschema/sch_text.cpp | 1777 ++++++++ eeschema/sch_text.h | 366 ++ eeschema/sch_validators.cpp | 141 + eeschema/sch_validators.h | 72 + eeschema/schedit.cpp | 1163 +++++ eeschema/schematic_undo_redo.cpp | 382 ++ eeschema/schframe.cpp | 1320 ++++++ eeschema/schframe.h | 1351 ++++++ eeschema/selpart.cpp | 163 + eeschema/sheet.cpp | 452 ++ eeschema/sheetlab.cpp | 179 + eeschema/symbdraw.cpp | 370 ++ eeschema/symbedit.cpp | 269 ++ eeschema/template_fieldnames.cpp | 211 + eeschema/template_fieldnames.h | 190 + eeschema/template_fieldnames.keywords | 5 + eeschema/tool_lib.cpp | 243 ++ eeschema/tool_sch.cpp | 325 ++ eeschema/tool_viewlib.cpp | 279 ++ eeschema/transform.cpp | 148 + eeschema/transform.h | 106 + eeschema/viewlib_frame.cpp | 595 +++ eeschema/viewlib_frame.h | 188 + eeschema/viewlibs.cpp | 310 ++ 293 files changed, 125869 insertions(+) create mode 100644 eeschema/CMakeLists.txt create mode 100644 eeschema/Info.plist create mode 100644 eeschema/annotate.cpp create mode 100644 eeschema/backanno.cpp create mode 100644 eeschema/block.cpp create mode 100644 eeschema/block_libedit.cpp create mode 100644 eeschema/bus-wire-junction.cpp create mode 100644 eeschema/busentry.cpp create mode 100644 eeschema/class_drc_erc_item.cpp create mode 100644 eeschema/class_libentry.cpp create mode 100644 eeschema/class_libentry.h create mode 100644 eeschema/class_library.cpp create mode 100644 eeschema/class_library.h create mode 100644 eeschema/class_netlist_object.cpp create mode 100644 eeschema/class_netlist_object.h create mode 100644 eeschema/class_sch_screen.h create mode 100644 eeschema/cmp_library.keywords create mode 100644 eeschema/cmp_library_lexer.cpp create mode 100644 eeschema/component_references_lister.cpp create mode 100644 eeschema/component_tree_search_container.cpp create mode 100644 eeschema/component_tree_search_container.h create mode 100644 eeschema/controle.cpp create mode 100644 eeschema/cross-probing.cpp create mode 100644 eeschema/dialog_erc_listbox.h create mode 100644 eeschema/dialogs/dialog_annotate.cpp create mode 100644 eeschema/dialogs/dialog_annotate_base.cpp create mode 100644 eeschema/dialogs/dialog_annotate_base.fbp create mode 100644 eeschema/dialogs/dialog_annotate_base.h create mode 100644 eeschema/dialogs/dialog_bom.cpp create mode 100644 eeschema/dialogs/dialog_bom_base.cpp create mode 100644 eeschema/dialogs/dialog_bom_base.fbp create mode 100644 eeschema/dialogs/dialog_bom_base.h create mode 100644 eeschema/dialogs/dialog_bom_cfg.keywords create mode 100644 eeschema/dialogs/dialog_bom_help.html create mode 100644 eeschema/dialogs/dialog_choose_component.cpp create mode 100644 eeschema/dialogs/dialog_choose_component.h create mode 100644 eeschema/dialogs/dialog_choose_component_base.cpp create mode 100644 eeschema/dialogs/dialog_choose_component_base.fbp create mode 100644 eeschema/dialogs/dialog_choose_component_base.h create mode 100644 eeschema/dialogs/dialog_color_config.cpp create mode 100644 eeschema/dialogs/dialog_color_config.h create mode 100644 eeschema/dialogs/dialog_color_config_base.cpp create mode 100644 eeschema/dialogs/dialog_color_config_base.fbp create mode 100644 eeschema/dialogs/dialog_color_config_base.h create mode 100644 eeschema/dialogs/dialog_edit_component_in_lib.cpp create mode 100644 eeschema/dialogs/dialog_edit_component_in_lib.h create mode 100644 eeschema/dialogs/dialog_edit_component_in_lib_base.cpp create mode 100644 eeschema/dialogs/dialog_edit_component_in_lib_base.fbp create mode 100644 eeschema/dialogs/dialog_edit_component_in_lib_base.h create mode 100644 eeschema/dialogs/dialog_edit_component_in_schematic.cpp create mode 100644 eeschema/dialogs/dialog_edit_component_in_schematic_fbp.cpp create mode 100644 eeschema/dialogs/dialog_edit_component_in_schematic_fbp.fbp create mode 100644 eeschema/dialogs/dialog_edit_component_in_schematic_fbp.h create mode 100644 eeschema/dialogs/dialog_edit_label.cpp create mode 100644 eeschema/dialogs/dialog_edit_label_base.cpp create mode 100644 eeschema/dialogs/dialog_edit_label_base.fbp create mode 100644 eeschema/dialogs/dialog_edit_label_base.h create mode 100644 eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp create mode 100644 eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.cpp create mode 100644 eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.fbp create mode 100644 eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.h create mode 100644 eeschema/dialogs/dialog_edit_one_field.cpp create mode 100644 eeschema/dialogs/dialog_edit_one_field.h create mode 100644 eeschema/dialogs/dialog_eeschema_config.cpp create mode 100644 eeschema/dialogs/dialog_eeschema_config_fbp.cpp create mode 100644 eeschema/dialogs/dialog_eeschema_config_fbp.fbp create mode 100644 eeschema/dialogs/dialog_eeschema_config_fbp.h create mode 100644 eeschema/dialogs/dialog_eeschema_options.cpp create mode 100644 eeschema/dialogs/dialog_eeschema_options.h create mode 100644 eeschema/dialogs/dialog_eeschema_options_base.cpp create mode 100644 eeschema/dialogs/dialog_eeschema_options_base.fbp create mode 100644 eeschema/dialogs/dialog_eeschema_options_base.h create mode 100644 eeschema/dialogs/dialog_erc.cpp create mode 100644 eeschema/dialogs/dialog_erc.h create mode 100644 eeschema/dialogs/dialog_erc_base.cpp create mode 100644 eeschema/dialogs/dialog_erc_base.fbp create mode 100644 eeschema/dialogs/dialog_erc_base.h create mode 100644 eeschema/dialogs/dialog_lib_edit_draw_item.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_draw_item.fbp create mode 100644 eeschema/dialogs/dialog_lib_edit_draw_item.h create mode 100644 eeschema/dialogs/dialog_lib_edit_draw_item_base.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_draw_item_base.h create mode 100644 eeschema/dialogs/dialog_lib_edit_pin.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin.h create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_base.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_base.fbp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_base.h create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_table.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_table.h create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp create mode 100644 eeschema/dialogs/dialog_lib_edit_pin_table_base.h create mode 100644 eeschema/dialogs/dialog_lib_edit_text.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_text.h create mode 100644 eeschema/dialogs/dialog_lib_edit_text_base.cpp create mode 100644 eeschema/dialogs/dialog_lib_edit_text_base.fbp create mode 100644 eeschema/dialogs/dialog_lib_edit_text_base.h create mode 100644 eeschema/dialogs/dialog_lib_new_component.cpp create mode 100644 eeschema/dialogs/dialog_lib_new_component.fbp create mode 100644 eeschema/dialogs/dialog_lib_new_component.h create mode 100644 eeschema/dialogs/dialog_lib_new_component_base.cpp create mode 100644 eeschema/dialogs/dialog_lib_new_component_base.h create mode 100644 eeschema/dialogs/dialog_libedit_options.cpp create mode 100644 eeschema/dialogs/dialog_libedit_options.h create mode 100644 eeschema/dialogs/dialog_libedit_options_base.cpp create mode 100644 eeschema/dialogs/dialog_libedit_options_base.fbp create mode 100644 eeschema/dialogs/dialog_libedit_options_base.h create mode 100644 eeschema/dialogs/dialog_netlist.cpp create mode 100644 eeschema/dialogs/dialog_netlist_base.cpp create mode 100644 eeschema/dialogs/dialog_netlist_base.fbp create mode 100644 eeschema/dialogs/dialog_netlist_base.h create mode 100644 eeschema/dialogs/dialog_plot_schematic.cpp create mode 100644 eeschema/dialogs/dialog_plot_schematic.h create mode 100644 eeschema/dialogs/dialog_plot_schematic_base.cpp create mode 100644 eeschema/dialogs/dialog_plot_schematic_base.fbp create mode 100644 eeschema/dialogs/dialog_plot_schematic_base.h create mode 100644 eeschema/dialogs/dialog_print_using_printer.cpp create mode 100644 eeschema/dialogs/dialog_print_using_printer_base.cpp create mode 100644 eeschema/dialogs/dialog_print_using_printer_base.fbp create mode 100644 eeschema/dialogs/dialog_print_using_printer_base.h create mode 100644 eeschema/dialogs/dialog_rescue_each.cpp create mode 100644 eeschema/dialogs/dialog_rescue_each_base.cpp create mode 100644 eeschema/dialogs/dialog_rescue_each_base.fbp create mode 100644 eeschema/dialogs/dialog_rescue_each_base.h create mode 100644 eeschema/dialogs/dialog_sch_edit_sheet_pin.cpp create mode 100644 eeschema/dialogs/dialog_sch_edit_sheet_pin.h create mode 100644 eeschema/dialogs/dialog_sch_edit_sheet_pin_base.cpp create mode 100644 eeschema/dialogs/dialog_sch_edit_sheet_pin_base.fbp create mode 100644 eeschema/dialogs/dialog_sch_edit_sheet_pin_base.h create mode 100644 eeschema/dialogs/dialog_sch_sheet_props.cpp create mode 100644 eeschema/dialogs/dialog_sch_sheet_props.fbp create mode 100644 eeschema/dialogs/dialog_sch_sheet_props.h create mode 100644 eeschema/dialogs/dialog_sch_sheet_props_base.cpp create mode 100644 eeschema/dialogs/dialog_sch_sheet_props_base.h create mode 100644 eeschema/dialogs/dialog_schematic_find.cpp create mode 100644 eeschema/dialogs/dialog_schematic_find.h create mode 100644 eeschema/dialogs/dialog_schematic_find_base.cpp create mode 100644 eeschema/dialogs/dialog_schematic_find_base.fbp create mode 100644 eeschema/dialogs/dialog_schematic_find_base.h create mode 100644 eeschema/edit_bitmap.cpp create mode 100644 eeschema/edit_component_in_schematic.cpp create mode 100644 eeschema/edit_label.cpp create mode 100644 eeschema/eeredraw.cpp create mode 100644 eeschema/eeschema.cpp create mode 100644 eeschema/eeschema.icns create mode 100644 eeschema/eeschema.rc create mode 100644 eeschema/eeschema_config.cpp create mode 100644 eeschema/eeschema_config.h create mode 100644 eeschema/eeschema_doc.icns create mode 100644 eeschema/eeschema_id.h create mode 100644 eeschema/erc.cpp create mode 100644 eeschema/erc.h create mode 100644 eeschema/events_called_functions_for_edit.cpp create mode 100644 eeschema/files-io.cpp create mode 100644 eeschema/find.cpp create mode 100644 eeschema/general.h create mode 100644 eeschema/getpart.cpp create mode 100644 eeschema/help_common_strings.h create mode 100644 eeschema/hierarch.cpp create mode 100644 eeschema/hotkeys.cpp create mode 100644 eeschema/hotkeys.h create mode 100644 eeschema/invoke_sch_dialog.h create mode 100644 eeschema/lib_arc.cpp create mode 100644 eeschema/lib_arc.h create mode 100644 eeschema/lib_bezier.cpp create mode 100644 eeschema/lib_bezier.h create mode 100644 eeschema/lib_circle.cpp create mode 100644 eeschema/lib_circle.h create mode 100644 eeschema/lib_collectors.cpp create mode 100644 eeschema/lib_collectors.h create mode 100644 eeschema/lib_draw_item.cpp create mode 100644 eeschema/lib_draw_item.h create mode 100644 eeschema/lib_export.cpp create mode 100644 eeschema/lib_field.cpp create mode 100644 eeschema/lib_field.h create mode 100644 eeschema/lib_pin.cpp create mode 100644 eeschema/lib_pin.h create mode 100644 eeschema/lib_polyline.cpp create mode 100644 eeschema/lib_polyline.h create mode 100644 eeschema/lib_rectangle.cpp create mode 100644 eeschema/lib_rectangle.h create mode 100644 eeschema/lib_text.cpp create mode 100644 eeschema/lib_text.h create mode 100644 eeschema/libarch.cpp create mode 100644 eeschema/libedit.cpp create mode 100644 eeschema/libedit_onleftclick.cpp create mode 100644 eeschema/libedit_onrightclick.cpp create mode 100644 eeschema/libedit_plot_component.cpp create mode 100644 eeschema/libedit_undo_redo.cpp create mode 100644 eeschema/libeditframe.cpp create mode 100644 eeschema/libeditframe.h create mode 100644 eeschema/libfield.cpp create mode 100644 eeschema/load_one_schematic_file.cpp create mode 100644 eeschema/menubar.cpp create mode 100644 eeschema/menubar_libedit.cpp create mode 100644 eeschema/netform.cpp create mode 100644 eeschema/netlist.cpp create mode 100644 eeschema/netlist.h create mode 100644 eeschema/netlist_exporters/netlist_exporter.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter.h create mode 100644 eeschema/netlist_exporters/netlist_exporter_cadstar.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_cadstar.h create mode 100644 eeschema/netlist_exporters/netlist_exporter_generic.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_generic.h create mode 100644 eeschema/netlist_exporters/netlist_exporter_kicad.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_kicad.h create mode 100644 eeschema/netlist_exporters/netlist_exporter_orcadpcb2.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_orcadpcb2.h create mode 100644 eeschema/netlist_exporters/netlist_exporter_pspice.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_pspice.h create mode 100644 eeschema/onleftclick.cpp create mode 100644 eeschema/onrightclick.cpp create mode 100644 eeschema/operations_on_items_lists.cpp create mode 100644 eeschema/pinedit.cpp create mode 100644 eeschema/plot_schematic_DXF.cpp create mode 100644 eeschema/plot_schematic_HPGL.cpp create mode 100644 eeschema/plot_schematic_PDF.cpp create mode 100644 eeschema/plot_schematic_PS.cpp create mode 100644 eeschema/plot_schematic_SVG.cpp create mode 100644 eeschema/plugins/CMakeLists.txt create mode 100644 eeschema/plugins/python_scripts/README-bom.txt create mode 100644 eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py create mode 100644 eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py create mode 100644 eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py create mode 100644 eeschema/plugins/python_scripts/bom_html_grouped_by_value.py create mode 100644 eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py create mode 100644 eeschema/plugins/python_scripts/bom_sorted_by_ref.py create mode 100644 eeschema/plugins/python_scripts/kicad_netlist_reader.py create mode 100644 eeschema/plugins/python_scripts/round_robin.py create mode 100644 eeschema/plugins/python_scripts/round_value_robin.py create mode 100644 eeschema/plugins/xsl_scripts/bom2csv.xsl create mode 100644 eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl create mode 100644 eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl create mode 100644 eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl create mode 100644 eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl create mode 100644 eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl create mode 100644 eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl create mode 100644 eeschema/project_rescue.cpp create mode 100644 eeschema/project_rescue.h create mode 100644 eeschema/protos.h create mode 100644 eeschema/sch_base_frame.cpp create mode 100644 eeschema/sch_base_frame.h create mode 100644 eeschema/sch_bitmap.cpp create mode 100644 eeschema/sch_bitmap.h create mode 100644 eeschema/sch_bus_entry.cpp create mode 100644 eeschema/sch_bus_entry.h create mode 100644 eeschema/sch_collectors.cpp create mode 100644 eeschema/sch_collectors.h create mode 100644 eeschema/sch_component.cpp create mode 100644 eeschema/sch_component.h create mode 100644 eeschema/sch_field.cpp create mode 100644 eeschema/sch_field.h create mode 100644 eeschema/sch_item_struct.cpp create mode 100644 eeschema/sch_item_struct.h create mode 100644 eeschema/sch_junction.cpp create mode 100644 eeschema/sch_junction.h create mode 100644 eeschema/sch_line.cpp create mode 100644 eeschema/sch_line.h create mode 100644 eeschema/sch_marker.cpp create mode 100644 eeschema/sch_marker.h create mode 100644 eeschema/sch_no_connect.cpp create mode 100644 eeschema/sch_no_connect.h create mode 100644 eeschema/sch_reference_list.h create mode 100644 eeschema/sch_screen.cpp create mode 100644 eeschema/sch_sheet.cpp create mode 100644 eeschema/sch_sheet.h create mode 100644 eeschema/sch_sheet_path.cpp create mode 100644 eeschema/sch_sheet_path.h create mode 100644 eeschema/sch_sheet_pin.cpp create mode 100644 eeschema/sch_text.cpp create mode 100644 eeschema/sch_text.h create mode 100644 eeschema/sch_validators.cpp create mode 100644 eeschema/sch_validators.h create mode 100644 eeschema/schedit.cpp create mode 100644 eeschema/schematic_undo_redo.cpp create mode 100644 eeschema/schframe.cpp create mode 100644 eeschema/schframe.h create mode 100644 eeschema/selpart.cpp create mode 100644 eeschema/sheet.cpp create mode 100644 eeschema/sheetlab.cpp create mode 100644 eeschema/symbdraw.cpp create mode 100644 eeschema/symbedit.cpp create mode 100644 eeschema/template_fieldnames.cpp create mode 100644 eeschema/template_fieldnames.h create mode 100644 eeschema/template_fieldnames.keywords create mode 100644 eeschema/tool_lib.cpp create mode 100644 eeschema/tool_sch.cpp create mode 100644 eeschema/tool_viewlib.cpp create mode 100644 eeschema/transform.cpp create mode 100644 eeschema/transform.h create mode 100644 eeschema/viewlib_frame.cpp create mode 100644 eeschema/viewlib_frame.h create mode 100644 eeschema/viewlibs.cpp (limited to 'eeschema') diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt new file mode 100644 index 00000000..eb06147a --- /dev/null +++ b/eeschema/CMakeLists.txt @@ -0,0 +1,383 @@ +# the map generation creates on Windows/gcc a lot of useless warnings +# so disable it on windows +if( WIN32 AND NOT CMAKE_CROSSCOMPILING ) + set( MAKE_LINK_MAPS false ) +else() + set( MAKE_LINK_MAPS true ) +endif() + +add_definitions( -DEESCHEMA ) + + +include_directories( BEFORE ${INC_BEFORE} ) +include_directories( + ./dialogs + ./netlist_exporters + ../common + ../common/dialogs + ${INC_AFTER} + ) + + +set( EESCHEMA_DLGS + dialogs/dialog_annotate.cpp + dialogs/dialog_annotate_base.cpp + dialogs/dialog_bom.cpp + dialogs/dialog_bom_base.cpp + dialogs/dialog_bom_cfg_keywords.cpp + dialogs/dialog_color_config.cpp + dialogs/dialog_color_config_base.cpp + dialogs/dialog_choose_component.cpp + dialogs/dialog_choose_component_base.cpp + dialogs/dialog_lib_edit_text.cpp + dialogs/dialog_lib_edit_text_base.cpp + dialogs/dialog_edit_component_in_lib.cpp + dialogs/dialog_edit_component_in_lib_base.cpp + dialogs/dialog_edit_component_in_schematic_fbp.cpp + dialogs/dialog_edit_component_in_schematic.cpp + dialogs/dialog_edit_label.cpp + dialogs/dialog_edit_label_base.cpp + dialogs/dialog_edit_libentry_fields_in_lib.cpp + dialogs/dialog_edit_libentry_fields_in_lib_base.cpp + dialogs/dialog_edit_one_field.cpp + dialogs/dialog_eeschema_config.cpp + dialogs/dialog_eeschema_config_fbp.cpp + dialogs/dialog_eeschema_options_base.cpp + dialogs/dialog_eeschema_options.cpp + dialogs/dialog_erc.cpp + dialogs/dialog_erc_base.cpp + dialogs/dialog_lib_edit_draw_item.cpp + dialogs/dialog_lib_edit_draw_item_base.cpp + dialogs/dialog_libedit_options_base.cpp + dialogs/dialog_libedit_options.cpp + dialogs/dialog_lib_edit_pin.cpp + dialogs/dialog_lib_edit_pin_base.cpp + dialogs/dialog_lib_edit_pin_table.cpp + dialogs/dialog_lib_edit_pin_table_base.cpp + dialogs/dialog_lib_new_component.cpp + dialogs/dialog_lib_new_component_base.cpp + dialogs/dialog_netlist.cpp + dialogs/dialog_netlist_base.cpp + dialogs/dialog_plot_schematic_base.cpp + dialogs/dialog_plot_schematic.cpp + dialogs/dialog_print_using_printer_base.cpp + dialogs/dialog_print_using_printer.cpp + dialogs/dialog_rescue_each.cpp + dialogs/dialog_rescue_each_base.cpp + dialogs/dialog_sch_edit_sheet_pin.cpp + dialogs/dialog_sch_edit_sheet_pin_base.cpp + dialogs/dialog_sch_sheet_props.cpp + dialogs/dialog_sch_sheet_props_base.cpp + dialogs/dialog_schematic_find.cpp + dialogs/dialog_schematic_find_base.cpp + ) + +set( EESCHEMA_SRCS + annotate.cpp + backanno.cpp + block.cpp + block_libedit.cpp + busentry.cpp + bus-wire-junction.cpp + class_drc_erc_item.cpp + class_libentry.cpp + class_library.cpp + class_netlist_object.cpp + cmp_library_keywords.cpp + cmp_library_lexer.cpp + component_references_lister.cpp + controle.cpp + cross-probing.cpp + ${EESCHEMA_DLGS} + edit_component_in_schematic.cpp + edit_bitmap.cpp + edit_label.cpp + eeredraw.cpp + eeschema.cpp + eeschema_config.cpp + erc.cpp + events_called_functions_for_edit.cpp + files-io.cpp + find.cpp + getpart.cpp + component_tree_search_container.cpp + hierarch.cpp + hotkeys.cpp + libarch.cpp + libedit.cpp + libeditframe.cpp + libedit_onleftclick.cpp + libedit_onrightclick.cpp + libedit_plot_component.cpp + libedit_undo_redo.cpp + lib_arc.cpp + lib_bezier.cpp + lib_circle.cpp + lib_collectors.cpp + lib_draw_item.cpp + lib_export.cpp + lib_field.cpp + lib_pin.cpp + lib_polyline.cpp + lib_rectangle.cpp + lib_text.cpp + libfield.cpp + load_one_schematic_file.cpp + menubar.cpp + menubar_libedit.cpp + netform.cpp + netlist.cpp + onleftclick.cpp + onrightclick.cpp + operations_on_items_lists.cpp + pinedit.cpp + plot_schematic_DXF.cpp + plot_schematic_HPGL.cpp + plot_schematic_PS.cpp + plot_schematic_PDF.cpp + plot_schematic_SVG.cpp + project_rescue.cpp + sch_base_frame.cpp + sch_bitmap.cpp + sch_bus_entry.cpp + sch_collectors.cpp + sch_component.cpp + sch_field.cpp + sch_item_struct.cpp + sch_junction.cpp + sch_line.cpp + sch_marker.cpp + sch_no_connect.cpp + sch_screen.cpp + sch_sheet.cpp + sch_sheet_path.cpp + sch_sheet_pin.cpp + sch_text.cpp + sch_validators.cpp + schedit.cpp + schematic_undo_redo.cpp + schframe.cpp + selpart.cpp + sheet.cpp + sheetlab.cpp + symbdraw.cpp + symbedit.cpp + template_fieldnames_keywords.cpp + template_fieldnames.cpp + tool_lib.cpp + tool_sch.cpp + tool_viewlib.cpp + transform.cpp + viewlib_frame.cpp + viewlibs.cpp + + netlist_exporters/netlist_exporter.cpp + netlist_exporters/netlist_exporter_cadstar.cpp + netlist_exporters/netlist_exporter_generic.cpp + netlist_exporters/netlist_exporter_kicad.cpp + netlist_exporters/netlist_exporter_orcadpcb2.cpp + netlist_exporters/netlist_exporter_pspice.cpp + ) + + +set( EESCHEMA_COMMON_SRCS + ../common/dialogs/dialog_page_settings.cpp + ../common/base_screen.cpp + ../common/eda_text.cpp + ../common/class_page_info.cpp + ../common/base_units.cpp + ) + + +if( MINGW ) + # EESCHEMA_RESOURCES variable is set by the macro. + mingw_resource_compiler( eeschema ) +else() + set( EESCHEMA_RESOURCES eeschema.rc ) +endif() + +# Create a C++ compilable string initializer containing html text into a *.h file: +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h + COMMAND ${CMAKE_COMMAND} + -DinputFile=${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html + -DoutputFile=${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h + -P ${CMAKE_MODULE_PATH}/Html2C.cmake + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html + COMMENT "creating ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h + from ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html" + ) + +set_source_files_properties( dialogs/dialog_bom.cpp + PROPERTIES + OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h + ) + +if( APPLE ) + # setup bundle + set( EESCHEMA_RESOURCES eeschema.icns eeschema_doc.icns ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/eeschema.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/eeschema_doc.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set( MACOSX_BUNDLE_ICON_FILE eeschema.icns ) + set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-pcb.kicad ) + set( MACOSX_BUNDLE_NAME eeschema ) +endif() + + +add_executable( eeschema WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ${EESCHEMA_RESOURCES} + ) +set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=FRAME_SCH;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL" + ) +target_link_libraries( eeschema + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + +# the DSO (KIFACE) housing the main eeschema code: +add_library( eeschema_kiface MODULE + ${EESCHEMA_SRCS} + ${EESCHEMA_COMMON_SRCS} + ) +target_link_libraries( eeschema_kiface + common + bitmaps + polygon + gal + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) +set_target_properties( eeschema_kiface PROPERTIES + # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like + # _eeschema.so, _eeschema.dll, or _eeschema.kiface + OUTPUT_NAME eeschema + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + +# The KIFACE is in eeschema.cpp, export it: +set_source_files_properties( eeschema.cpp PROPERTIES + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + +# if building eeschema, then also build eeschema_kiface if out of date. +add_dependencies( eeschema eeschema_kiface ) + +if( MAKE_LINK_MAPS ) + # generate link map with cross reference + set_target_properties( eeschema_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=${KIFACE_PREFIX}eeschema${KIFACE_SUFFIX}.map" + ) + set_target_properties( eeschema PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=eeschema.map" + ) +endif() + +# these 2 binaries are a matched set, keep them together: +if( APPLE ) + set_target_properties( eeschema PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + + # puts binaries into the *.app bundle while linking + set_target_properties( eeschema_kiface PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${OSX_BUNDLE_BUILD_KIFACE_DIR} + ) + # put individual bundle outside of main bundle as a first step + # will be pulled into the main bundle when creating main bundle + install( TARGETS eeschema + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + install( CODE " + # override default embedded path settings + ${OSX_BUNDLE_OVERRIDE_PATHS} + + # do all the work + include( BundleUtilities ) + fixup_bundle( ${KICAD_BIN}/eeschema.app/Contents/MacOS/eeschema + \"\" + \"\" + ) + " COMPONENT Runtime + ) +else() + install( TARGETS eeschema + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + install( TARGETS eeschema_kiface + # actual filename subject to change at milestone C) + # modular-kicad blueprint. + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) +endif() + +# auto-generate cmp_library_lexer.h and cmp_library_keywords.cpp for the component +# library format. +make_lexer( + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library.keywords + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_keywords.cpp + TLIB_T + ) + +add_custom_target( + cmp_library_lexer_source_files ALL + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_keywords.cpp + ) + +add_dependencies( eeschema_kiface cmp_library_lexer_source_files ) + +make_lexer( + ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames.keywords + ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames_keywords.cpp + TFIELD_T + + # Pass header file with dependency on *_lexer.h as extra_arg + template_fieldnames.h + ) + +add_custom_target( + field_template_lexer_source_files ALL + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames_keywords.cpp + ) + +add_dependencies( eeschema_kiface field_template_lexer_source_files ) + +make_lexer( + ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg.keywords + ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_keywords.cpp + T_BOMCFG_T + + # Pass header file with dependency on *_lexer.h as extra_arg + dialogs/dialog_bom_cfg.h + ) + +add_custom_target( + dialog_bom_cfg_lexer_source_files ALL + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_keywords.cpp + ) + +add_dependencies( eeschema_kiface dialog_bom_cfg_lexer_source_files ) + +add_subdirectory( plugins ) diff --git a/eeschema/Info.plist b/eeschema/Info.plist new file mode 100644 index 00000000..7d8663d2 --- /dev/null +++ b/eeschema/Info.plist @@ -0,0 +1,35 @@ + + + + + CFBundleDocumentTypes + + + CFBundleTypeRole Editor + CFBundleTypeExtensions + + sch + + CFBundleTypeIconFile eeschema_doc.icns + CFBundleTypeName eeschema document + LSHandlerRank Owner + + + CFBundleDevelopmentRegion English + CFBundleExecutable eeschema + CFBundleGetInfoString + CFBundleIconFile eeschema.icns + CFBundleIdentifier org.kicad-pcb.eeschema + CFBundleInfoDictionaryVersion 6.0 + CFBundleLongVersionString + CFBundleName EESchema + CFBundlePackageType APPL + CFBundleShortVersionString + CFBundleSignature ???? + CFBundleVersion + CSResourcesFileMapped + LSRequiresCarbon + NSHumanReadableCopyright + NSHighResolutionCapable True + + diff --git a/eeschema/annotate.cpp b/eeschema/annotate.cpp new file mode 100644 index 00000000..1b2a27d2 --- /dev/null +++ b/eeschema/annotate.cpp @@ -0,0 +1,200 @@ +/** + * @file annotate.cpp + * @brief Component annotation. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2013 KiCad Developers, see change_log.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 + +#include +#include +#include +#include + +#include +#include + +void SCH_EDIT_FRAME::DeleteAnnotation( bool aCurrentSheetOnly ) +{ + if( aCurrentSheetOnly ) + { + SCH_SCREEN* screen = GetScreen(); + wxCHECK_RET( screen != NULL, wxT( "Attempt to clear annotation of a NULL screen." ) ); + screen->ClearAnnotation( m_CurrentSheet ); + } + else + { + SCH_SCREENS ScreenList; + ScreenList.ClearAnnotation(); + } + + // Update the references for the sheet that is currently being displayed. + m_CurrentSheet->UpdateAllScreenReferences(); + GetCanvas()->Refresh(); + OnModify(); +} + + +void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic, + ANNOTATE_ORDER_T aSortOption, + ANNOTATE_OPTION_T aAlgoOption, + bool aResetAnnotation, + bool aRepairTimestamps, + bool aLockUnits ) +{ + SCH_REFERENCE_LIST references; + + SCH_SCREENS screens; + + // Build the sheet list. + SCH_SHEET_LIST sheets; + + // Map of locked components + SCH_MULTI_UNIT_REFERENCE_MAP lockedComponents; + + // Test for and replace duplicate time stamps in components and sheets. Duplicate + // time stamps can happen with old schematics, schematic conversions, or manual + // editing of files. + if( aRepairTimestamps ) + { + int count = screens.ReplaceDuplicateTimeStamps(); + + if( count ) + { + wxString msg; + msg.Printf( _( "%d duplicate time stamps were found and replaced." ), count ); + DisplayInfoMessage( NULL, msg, 2 ); + } + } + + // If units must be locked, collect all the sets that must be annotated together. + if( aLockUnits ) + { + if( aAnnotateSchematic ) + { + sheets.GetMultiUnitComponents( Prj().SchLibs(), lockedComponents ); + } + else + { + m_CurrentSheet->GetMultiUnitComponents( Prj().SchLibs(), lockedComponents ); + } + } + + // If it is an annotation for all the components, reset previous annotation. + if( aResetAnnotation ) + DeleteAnnotation( !aAnnotateSchematic ); + + // Set sheet number and number of sheets. + SetSheetNumberAndCount(); + + // Build component list + if( aAnnotateSchematic ) + { + sheets.GetComponents( Prj().SchLibs(), references ); + } + else + { + m_CurrentSheet->GetComponents( Prj().SchLibs(), references ); + } + + // Break full components reference in name (prefix) and number: + // example: IC1 become IC, and 1 + references.SplitReferences(); + + switch( aSortOption ) + { + default: + case SORT_BY_X_POSITION: + references.SortByXCoordinate(); + break; + + case SORT_BY_Y_POSITION: + references.SortByYCoordinate(); + break; + } + + bool useSheetNum = false; + int idStep = 100; + + switch( aAlgoOption ) + { + default: + case INCREMENTAL_BY_REF: + break; + + case SHEET_NUMBER_X_100: + useSheetNum = true; + break; + + case SHEET_NUMBER_X_1000: + useSheetNum = true; + idStep = 1000; + break; + } + + // Recalculate and update reference numbers in schematic + references.Annotate( useSheetNum, idStep, lockedComponents ); + references.UpdateAnnotation(); + + wxArrayString errors; + + // Final control (just in case ... ). + if( CheckAnnotate( &errors, !aAnnotateSchematic ) ) + { + wxString msg; + + for( size_t i = 0; i < errors.GetCount(); i++ ) + msg += errors[i]; + + // wxLogWarning is a cheap and dirty way to dump a potentially long list of + // strings to a dialog that can be saved to a file. This should be replaced + // by a more elegant solution. + wxLogWarning( msg ); + } + + OnModify(); + + // Update on screen references, that can be modified by previous calculations: + m_CurrentSheet->UpdateAllScreenReferences(); + SetSheetNumberAndCount(); + + m_canvas->Refresh( true ); +} + + +int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly ) +{ + // build the screen list + SCH_SHEET_LIST SheetList; + SCH_REFERENCE_LIST ComponentsList; + + // Build the list of components + if( !aOneSheetOnly ) + SheetList.GetComponents( Prj().SchLibs(), ComponentsList ); + else + m_CurrentSheet->GetComponents( Prj().SchLibs(), ComponentsList ); + + return ComponentsList.CheckAnnotation( aMessageList ); +} diff --git a/eeschema/backanno.cpp b/eeschema/backanno.cpp new file mode 100644 index 00000000..671f727b --- /dev/null +++ b/eeschema/backanno.cpp @@ -0,0 +1,264 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2013 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file backanno.cpp + * @brief Functions for backannotating footprint information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +void SCH_EDIT_FRAME::backAnnotateFootprints( const std::string& aChangedSetOfReferences ) + throw( IO_ERROR, boost::bad_pointer ) +{ + // Build a flat list of components in schematic: + SCH_REFERENCE_LIST refs; + SCH_SHEET_LIST sheets; + bool isChanged = false; + + sheets.GetComponents( Prj().SchLibs(), refs, false ); + + DSNLEXER lexer( aChangedSetOfReferences, FROM_UTF8( __func__ ) ); + PTREE doc; + + try + { + Scan( &doc, &lexer ); + +#if defined(DEBUG) && 0 + STRING_FORMATTER sf; + Format( &sf, 0, 0, doc ); + printf( "%s: '%s'\n", __func__, sf.GetString().c_str() ); +#endif + + CPTREE& back_anno = doc.get_child( "back_annotation" ); + wxString footprint; + + for( PTREE::const_iterator ref = back_anno.begin(); ref != back_anno.end(); ++ref ) + { + wxASSERT( ref->first == "ref" ); + + wxString reference = (UTF8&) ref->second.front().first; + + // Ensure the "fpid" node contains a footprint name, + // and get it if exists + if( ref->second.get_child( "fpid" ).size() ) + { + wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first; + footprint = tmp; + } + else + footprint.Empty(); + + // DBG( printf( "%s: ref:%s fpid:%s\n", __func__, TO_UTF8( reference ), TO_UTF8( footprint ) ); ) + + // Search the component in the flat list + for( unsigned ii = 0; ii < refs.GetCount(); ++ii ) + { + if( Cmp_KEEPCASE( reference, refs[ii].GetRef() ) == 0 ) + { + // We have found a candidate. + // Note: it can be not unique (multiple parts per package) + // So we *do not* stop the search here + SCH_COMPONENT* component = refs[ii].GetComp(); + SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); + const wxString& oldfp = fpfield->GetText(); + + if( !oldfp && fpfield->IsVisible() ) + { + fpfield->SetVisible( false ); + } + + // DBG( printf("%s: ref:%s fpid:%s\n", __func__, TO_UTF8( refs[ii].GetRef() ), TO_UTF8( footprint ) );) + if( oldfp != footprint ) + isChanged = true; + + fpfield->SetText( footprint ); + } + } + } + } + catch( const PTREE_ERROR& ex ) + { + // remap the exception to something the caller is likely to understand. + THROW_IO_ERROR( ex.what() ); + } + + if( isChanged ) + OnModify(); +} + + +bool SCH_EDIT_FRAME::ProcessCmpToFootprintLinkFile( const wxString& aFullFilename, + bool aForceVisibilityState, + bool aVisibilityState ) +{ + // Build a flat list of components in schematic: + SCH_REFERENCE_LIST referencesList; + SCH_SHEET_LIST sheetList; + + sheetList.GetComponents( Prj().SchLibs(), referencesList, false ); + + FILE* cmpFile = wxFopen( aFullFilename, wxT( "rt" ) ); + + if( cmpFile == NULL ) + return false; + + // cmpFileReader dtor will close cmpFile + FILE_LINE_READER cmpFileReader( cmpFile, aFullFilename ); + + // Now, for each component found in file, + // replace footprint field value by the new value: + wxString reference; + wxString footprint; + wxString buffer; + wxString value; + + while( cmpFileReader.ReadLine() ) + { + buffer = FROM_UTF8( cmpFileReader.Line() ); + + if( !buffer.StartsWith( wxT( "BeginCmp" ) ) ) + continue; + + // Begin component description. + reference.Empty(); + footprint.Empty(); + + while( cmpFileReader.ReadLine() ) + { + buffer = FROM_UTF8( cmpFileReader.Line() ); + + if( buffer.StartsWith( wxT( "EndCmp" ) ) ) + break; + + // store string value, stored between '=' and ';' delimiters. + value = buffer.AfterFirst( '=' ); + value = value.BeforeLast( ';' ); + value.Trim(true); + value.Trim(false); + + if( buffer.StartsWith( wxT( "Reference" ) ) ) + { + reference = value; + } + else if( buffer.StartsWith( wxT( "IdModule" ) ) ) + { + footprint = value; + } + } + + // A block is read: initialize the footprint field of the corresponding component + // if the footprint name is not empty + if( reference.IsEmpty() ) + continue; + + // Search the component in the flat list + for( unsigned ii = 0; ii < referencesList.GetCount(); ii++ ) + { + if( Cmp_KEEPCASE( reference, referencesList[ii].GetRef() ) == 0 ) + { + // We have found a candidate. + // Note: it can be not unique (multiple units per part) + // So we *do not* stop the search here + SCH_COMPONENT* component = referencesList[ii].GetComp(); + SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); + + fpfield->SetText( footprint ); + + if( aForceVisibilityState ) + { + component->GetField( FOOTPRINT )->SetVisible( aVisibilityState ); + } + } + } + } + + return true; +} + + +bool SCH_EDIT_FRAME::LoadCmpToFootprintLinkFile() +{ + wxString path = wxPathOnly( Prj().GetProjectFullName() ); + + wxFileDialog dlg( this, _( "Load Component Footprint Link File" ), + path, wxEmptyString, + ComponentFileExtensionWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + wxString filename = dlg.GetPath(); + wxString title = wxT( "Eeschema " ) + GetBuildVersion() + wxT( ' ' ) + filename; + + SetTitle( title ); + + wxArrayString choices; + choices.Add( _( "Keep existing footprint field visibility" ) ); + choices.Add( _( "Show all footprint fields" ) ); + choices.Add( _( "Hide all footprint fields" ) ); + + wxSingleChoiceDialog choiceDlg( this, _( "Select the footprint field visibility setting." ), + _( "Change Visibility" ), choices ); + + + if( choiceDlg.ShowModal() == wxID_CANCEL ) + return false; + + bool forceVisibility = (choiceDlg.GetSelection() != 0 ); + bool visibilityState = (choiceDlg.GetSelection() == 1 ); + + if( !ProcessCmpToFootprintLinkFile( filename, forceVisibility, visibilityState ) ) + { + wxString msg = wxString::Format( _( "Failed to open component-footprint link file '%s'" ), + filename.GetData() ); + + DisplayError( this, msg ); + return false; + } + + OnModify(); + return true; +} diff --git a/eeschema/block.cpp b/eeschema/block.cpp new file mode 100644 index 00000000..e4b38e9f --- /dev/null +++ b/eeschema/block.cpp @@ -0,0 +1,538 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2009-2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema/block.cpp + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Imported functions: +extern void SetSchItemParent( SCH_ITEM* Struct, SCH_SCREEN* Screen ); +extern void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint aMoveVector ); +extern void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, wxPoint& Center ); +extern void MirrorX( PICKED_ITEMS_LIST& aItemsList, wxPoint& aMirrorPoint ); +extern void MirrorY( PICKED_ITEMS_LIST& aItemsList, wxPoint& Center ); +extern void DuplicateItemsInList( SCH_SCREEN* screen, + PICKED_ITEMS_LIST& aItemsList, + const wxPoint aMoveVector ); + +static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aPosition, bool aErase ); + + +int SCH_EDIT_FRAME::BlockCommand( int key ) +{ + int cmd = BLOCK_IDLE; + + switch( key ) + { + default: + cmd = key & 0xFF; + break; + + case 0: + cmd = BLOCK_MOVE; + break; + + case GR_KB_SHIFT: + cmd = BLOCK_COPY; + break; + + case GR_KB_ALT: + cmd = BLOCK_ROTATE; + break; + + case GR_KB_CTRL: + cmd = BLOCK_DRAG; + break; + + case GR_KB_SHIFTCTRL: + cmd = BLOCK_DELETE; + break; + + case MOUSE_MIDDLE: + cmd = BLOCK_ZOOM; + break; + } + + return cmd; +} + + +void SCH_EDIT_FRAME::InitBlockPasteInfos() +{ + BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate; + + block->GetItems().CopyList( m_blockItems.GetItems() ); + m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); +} + + +void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) +{ + BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate; + + if( !m_canvas->IsMouseCaptured() ) + { + DisplayError( this, wxT( "HandleBlockPLace() : m_mouseCaptureCallback = NULL" ) ); + } + + if( block->GetCount() == 0 ) + { + wxString msg; + msg.Printf( wxT( "HandleBlockPLace() error : no items to place (cmd %d, state %d)" ), + block->GetCommand(), block->GetState() ); + DisplayError( this, msg ); + } + + block->SetState( STATE_BLOCK_STOP ); + + switch( block->GetCommand() ) + { + case BLOCK_DRAG: // Drag from mouse + case BLOCK_DRAG_ITEM: // Drag from a component selection and drag command + case BLOCK_MOVE: + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + SaveCopyInUndoList( block->GetItems(), UR_MOVED, block->GetMoveVector() ); + MoveItemsInList( block->GetItems(), block->GetMoveVector() ); + block->ClearItemsList(); + break; + + case BLOCK_COPY: /* Copy */ + case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/ + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + DuplicateItemsInList( GetScreen(), block->GetItems(), block->GetMoveVector() ); + + SaveCopyInUndoList( block->GetItems(), + ( block->GetCommand() == BLOCK_PRESELECT_MOVE ) ? UR_CHANGED : UR_NEW ); + + block->ClearItemsList(); + break; + + case BLOCK_PASTE: + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + PasteListOfItems( DC ); + block->ClearItemsList(); + break; + + default: // others are handled by HandleBlockEnd() + break; + } + + OnModify(); + + // clear dome flags and pointers + GetScreen()->ClearDrawingState(); + GetScreen()->ClearBlockCommand(); + GetScreen()->SetCurItem( NULL ); + GetScreen()->TestDanglingEnds( m_canvas, DC ); + + if( block->GetCount() ) + { + DisplayError( this, wxT( "HandleBlockPLace() error: some items left in buffer" ) ); + block->ClearItemsList(); + } + + m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString, false ); + m_canvas->Refresh(); +} + + +bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) +{ + bool nextcmd = false; + bool zoom_command = false; + BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate; + + if( block->GetCount() ) + { + BLOCK_STATE_T state = block->GetState(); + BLOCK_COMMAND_T command = block->GetCommand(); + + m_canvas->CallEndMouseCapture( aDC ); + + block->SetState( state ); + block->SetCommand( command ); + m_canvas->SetMouseCapture( DrawAndSizingBlockOutlines, AbortBlockCurrentCommand ); + SetCrossHairPosition( block->GetEnd() ); + + if( block->GetCommand() != BLOCK_ABORT ) + m_canvas->MoveCursorToCrossHair(); + } + + if( m_canvas->IsMouseCaptured() ) + { + switch( block->GetCommand() ) + { + case BLOCK_IDLE: + DisplayError( this, wxT( "Error in HandleBlockPLace()" ) ); + break; + + case BLOCK_ROTATE: + GetScreen()->UpdatePickList(); + DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false ); + + if( block->GetCount() ) + { + // Compute the rotation center and put it on grid: + wxPoint rotationPoint = block->Centre(); + rotationPoint = GetNearestGridPosition( rotationPoint ); + SetCrossHairPosition( rotationPoint ); + SaveCopyInUndoList( block->GetItems(), UR_ROTATED, rotationPoint ); + RotateListOfItems( block->GetItems(), rotationPoint ); + OnModify(); + } + + block->ClearItemsList(); + GetScreen()->TestDanglingEnds( m_canvas, aDC ); + m_canvas->Refresh(); + break; + + case BLOCK_DRAG: + case BLOCK_DRAG_ITEM: // Drag from a drag command + GetScreen()->BreakSegmentsOnJunctions(); + // fall through + + case BLOCK_MOVE: + case BLOCK_COPY: + if( block->GetCommand() == BLOCK_DRAG_ITEM && + GetScreen()->GetCurItem() != NULL ) + { + // This is a drag command, not a mouse block command + // Only this item is put in list + ITEM_PICKER picker; + picker.SetItem( GetScreen()->GetCurItem() ); + block->PushItem( picker ); + } + else + { + // Collect all items in the locate block + GetScreen()->UpdatePickList(); + } + // fall through + + case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/ + if( block->GetCount() ) + { + nextcmd = true; + GetScreen()->SelectBlockItems(); + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); + m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); + block->SetState( STATE_BLOCK_MOVE ); + } + else + { + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); + m_canvas->SetMouseCapture( NULL, NULL ); + } + break; + + case BLOCK_DELETE: + GetScreen()->UpdatePickList(); + DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false ); + + if( block->GetCount() ) + { + DeleteItemsInList( m_canvas, block->GetItems() ); + OnModify(); + } + block->ClearItemsList(); + GetScreen()->TestDanglingEnds( m_canvas, aDC ); + m_canvas->Refresh(); + break; + + case BLOCK_SAVE: // Save a copy of items in paste buffer + GetScreen()->UpdatePickList(); + DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false ); + + if( block->GetCount() ) + { + wxPoint move_vector = -GetScreen()->m_BlockLocate.GetLastCursorPosition(); + copyBlockItems( block->GetItems() ); + MoveItemsInList( m_blockItems.GetItems(), move_vector ); + } + + block->ClearItemsList(); + break; + + case BLOCK_PASTE: + block->SetState( STATE_BLOCK_MOVE ); + break; + + case BLOCK_ZOOM: + zoom_command = true; + break; + + case BLOCK_MIRROR_X: + GetScreen()->UpdatePickList(); + DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false ); + + if( block->GetCount() ) + { + // Compute the mirror center and put it on grid. + wxPoint mirrorPoint = block->Centre(); + mirrorPoint = GetNearestGridPosition( mirrorPoint ); + SetCrossHairPosition( mirrorPoint ); + SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_X, mirrorPoint ); + MirrorX( block->GetItems(), mirrorPoint ); + OnModify(); + } + + GetScreen()->TestDanglingEnds( m_canvas, aDC ); + m_canvas->Refresh(); + break; + + case BLOCK_MIRROR_Y: + GetScreen()->UpdatePickList(); + DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false ); + + if( block->GetCount() ) + { + // Compute the mirror center and put it on grid. + wxPoint mirrorPoint = block->Centre(); + mirrorPoint = GetNearestGridPosition( mirrorPoint ); + SetCrossHairPosition( mirrorPoint ); + SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_Y, mirrorPoint ); + MirrorY( block->GetItems(), mirrorPoint ); + OnModify(); + } + + GetScreen()->TestDanglingEnds( m_canvas, aDC ); + m_canvas->Refresh(); + break; + + default: + break; + } + } + + if( block->GetCommand() == BLOCK_ABORT ) + { + GetScreen()->ClearDrawingState(); + m_canvas->Refresh(); + } + + if( ! nextcmd ) + { + block->SetState( STATE_NO_BLOCK ); + block->SetCommand( BLOCK_IDLE ); + GetScreen()->SetCurItem( NULL ); + m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString, + false ); + } + + if( zoom_command ) + Window_Zoom( GetScreen()->m_BlockLocate ); + + return nextcmd; +} + + +/* Traces the outline of the search block structures + * The entire block follows the cursor + */ +static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + BASE_SCREEN* screen = aPanel->GetScreen(); + BLOCK_SELECTOR* block = &screen->m_BlockLocate; + SCH_ITEM* schitem; + + /* Erase old block contents. */ + if( aErase ) + { + block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() ); + + for( unsigned ii = 0; ii < block->GetCount(); ii++ ) + { + schitem = (SCH_ITEM*) block->GetItem( ii ); + + if( schitem->Type() == SCH_COMPONENT_T ) + ((SCH_COMPONENT*)schitem)->Draw( aPanel, aDC, block->GetMoveVector(), + g_XorMode, g_GhostColor, false ); + else + schitem->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, g_GhostColor ); + } + } + + /* Repaint new view. */ + block->SetMoveVector( aPanel->GetParent()->GetCrossHairPosition() - block->GetLastCursorPosition() ); + block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() ); + + for( unsigned ii = 0; ii < block->GetCount(); ii++ ) + { + schitem = (SCH_ITEM*) block->GetItem( ii ); + + if( schitem->Type() == SCH_COMPONENT_T ) + ((SCH_COMPONENT*)schitem)->Draw( aPanel, aDC, block->GetMoveVector(), + g_XorMode, g_GhostColor, false ); + else + schitem->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, g_GhostColor ); + } +} + + +void SCH_EDIT_FRAME::copyBlockItems( PICKED_ITEMS_LIST& aItemsList ) +{ + m_blockItems.ClearListAndDeleteItems(); // delete previous saved list, if exists + + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + // Clear m_Flag member of selected items: + aItemsList.GetPickedItem( ii )->ClearFlags(); + + /* Make a copy of the original picked item. */ + SCH_ITEM* copy = DuplicateStruct( (SCH_ITEM*) aItemsList.GetPickedItem( ii ) ); + copy->SetParent( NULL ); + + // In list the wrapper is owner of the schematic item, we can use the UR_DELETED + // status for the picker because pickers with this status are owner of the picked item + // (or TODO ?: create a new status like UR_DUPLICATE) + ITEM_PICKER item( copy, UR_DELETED ); + + m_blockItems.PushItem( item ); + } +} + + +void SCH_EDIT_FRAME::PasteListOfItems( wxDC* DC ) +{ + unsigned i; + SCH_ITEM* item; + SCH_SHEET_LIST hierarchy; // This is the entire schematic hierarcy. + + if( m_blockItems.GetCount() == 0 ) + { + DisplayError( this, _( "No item to paste." ) ); + return; + } + + wxFileName destFn = m_CurrentSheet->Last()->GetFileName(); + + if( destFn.IsRelative() ) + destFn.MakeAbsolute( Prj().GetProjectPath() ); + + // Make sure any sheets in the block to be pasted will not cause recursion in + // the destination sheet. + for( i = 0; i < m_blockItems.GetCount(); i++ ) + { + item = (SCH_ITEM*) m_blockItems.GetItem( i ); + + if( item->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*)item; + wxFileName srcFn = sheet->GetFileName(); + + if( srcFn.IsRelative() ) + srcFn.MakeAbsolute( Prj().GetProjectPath() ); + + SCH_SHEET_LIST sheetHierarchy( sheet ); + + if( hierarchy.TestForRecursion( sheetHierarchy, + destFn.GetFullPath( wxPATH_UNIX ) ) ) + { + wxString msg; + + msg.Printf( _( "The sheet changes cannot be made because the destination " + "sheet already has the sheet <%s> or one of it's subsheets " + "as a parent somewhere in the schematic hierarchy." ), + GetChars( sheet->GetFileName() ) ); + DisplayError( this, msg ); + return; + } + + // Duplicate sheet names and sheet time stamps are not valid. Use a time stamp + // based sheet name and update the time stamp for each sheet in the block. + unsigned long timeStamp = (unsigned long)GetNewTimeStamp(); + + sheet->SetName( wxString::Format( wxT( "sheet%8.8lX" ), timeStamp ) ); + sheet->SetTimeStamp( (time_t)timeStamp ); + } + } + + PICKED_ITEMS_LIST picklist; + + for( i = 0; i < m_blockItems.GetCount(); i++ ) + { + item = DuplicateStruct( (SCH_ITEM*) m_blockItems.GetItem( i ) ); + + // Creates data, and push it as new data in undo item list buffer + ITEM_PICKER picker( item, UR_NEW ); + picklist.PushItem( picker ); + + // Clear annotation and init new time stamp for the new components and sheets: + if( item->Type() == SCH_COMPONENT_T ) + { + ( (SCH_COMPONENT*) item )->SetTimeStamp( GetNewTimeStamp() ); + ( (SCH_COMPONENT*) item )->ClearAnnotation( NULL ); + } + else if( item->Type() == SCH_SHEET_T ) + { + ( (SCH_SHEET*) item )->SetTimeStamp( GetNewTimeStamp() ); + } + + SetSchItemParent( item, GetScreen() ); + item->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + GetScreen()->Append( item ); + } + + SaveCopyInUndoList( picklist, UR_NEW ); + + MoveItemsInList( picklist, GetScreen()->m_BlockLocate.GetMoveVector() ); + + // Clear flags for all items. + GetScreen()->ClearDrawingState(); + + OnModify(); + + return; +} diff --git a/eeschema/block_libedit.cpp b/eeschema/block_libedit.cpp new file mode 100644 index 00000000..5dc235f7 --- /dev/null +++ b/eeschema/block_libedit.cpp @@ -0,0 +1,355 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file block_libedit.cpp + */ + +#include +#include +#include +#include + +#include +#include +#include + + +static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ); + + +int LIB_EDIT_FRAME::BlockCommand( int key ) +{ + int cmd = BLOCK_IDLE; + + switch( key ) + { + default: + cmd = key & 0xFF; + break; + + case -1: + cmd = BLOCK_PRESELECT_MOVE; + break; + + case 0: + cmd = BLOCK_MOVE; + break; + + case GR_KB_SHIFT: + cmd = BLOCK_COPY; + break; + + case GR_KB_ALT: + cmd = BLOCK_ROTATE; + break; + + case GR_KB_SHIFTCTRL: + cmd = BLOCK_DELETE; + break; + + case GR_KB_CTRL: + cmd = BLOCK_MIRROR_Y; + break; + + case MOUSE_MIDDLE: + cmd = BLOCK_ZOOM; + break; + } + + return cmd; +} + + +bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) +{ + int ItemCount = 0; + bool nextCmd = false; + wxPoint pt; + + if( GetScreen()->m_BlockLocate.GetCount() ) + { + BLOCK_STATE_T state = GetScreen()->m_BlockLocate.GetState(); + BLOCK_COMMAND_T command = GetScreen()->m_BlockLocate.GetCommand(); + m_canvas->CallEndMouseCapture( DC ); + GetScreen()->m_BlockLocate.SetState( state ); + GetScreen()->m_BlockLocate.SetCommand( command ); + m_canvas->SetMouseCapture( DrawAndSizingBlockOutlines, AbortBlockCurrentCommand ); + SetCrossHairPosition( wxPoint( GetScreen()->m_BlockLocate.GetRight(), + GetScreen()->m_BlockLocate.GetBottom() ) ); + m_canvas->MoveCursorToCrossHair(); + } + + switch( GetScreen()->m_BlockLocate.GetCommand() ) + { + case BLOCK_IDLE: + DisplayError( this, wxT( "Error in HandleBlockPLace" ) ); + break; + + case BLOCK_DRAG: // Drag + case BLOCK_DRAG_ITEM: + case BLOCK_MOVE: // Move + case BLOCK_COPY: // Copy + if( GetCurPart() ) + ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate, + m_unit, m_convert, + m_editPinsPerPartOrConvert ); + if( ItemCount ) + { + nextCmd = true; + + if( m_canvas->IsMouseCaptured() ) + { + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + } + + GetScreen()->m_BlockLocate.SetState( STATE_BLOCK_MOVE ); + m_canvas->Refresh( true ); + } + break; + + case BLOCK_PRESELECT_MOVE: // Move with preselection list + nextCmd = true; + m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); + GetScreen()->m_BlockLocate.SetState( STATE_BLOCK_MOVE ); + break; + + case BLOCK_DELETE: // Delete + if( GetCurPart() ) + ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate, + m_unit, m_convert, + m_editPinsPerPartOrConvert ); + if( ItemCount ) + SaveCopyInUndoList( GetCurPart() ); + + if( GetCurPart() ) + { + GetCurPart()->DeleteSelectedItems(); + OnModify(); + } + break; + + case BLOCK_SAVE: // Save + case BLOCK_PASTE: + case BLOCK_FLIP: + break; + + case BLOCK_ROTATE: + case BLOCK_MIRROR_X: + case BLOCK_MIRROR_Y: + if( GetCurPart() ) + ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate, + m_unit, m_convert, + m_editPinsPerPartOrConvert ); + if( ItemCount ) + SaveCopyInUndoList( GetCurPart() ); + + pt = GetScreen()->m_BlockLocate.Centre(); + pt = GetNearestGridPosition( pt ); + pt.y = -pt.y; + + if( GetCurPart() ) + { + OnModify(); + int block_cmd = GetScreen()->m_BlockLocate.GetCommand(); + + if( block_cmd == BLOCK_MIRROR_Y) + GetCurPart()->MirrorSelectedItemsH( pt ); + else if( block_cmd == BLOCK_MIRROR_X) + GetCurPart()->MirrorSelectedItemsV( pt ); + else if( block_cmd == BLOCK_ROTATE ) + GetCurPart()->RotateSelectedItems( pt ); + } + + break; + + case BLOCK_ZOOM: // Window Zoom + Window_Zoom( GetScreen()->m_BlockLocate ); + break; + + case BLOCK_ABORT: + break; + + case BLOCK_SELECT_ITEMS_ONLY: + break; + + case BLOCK_COPY_AND_INCREMENT: // not used in Eeschema + case BLOCK_MOVE_EXACT: // not used in Eeschema + break; + } + + if( !nextCmd ) + { + if( GetScreen()->m_BlockLocate.GetCommand() != BLOCK_SELECT_ITEMS_ONLY && GetCurPart() ) + GetCurPart()->ClearSelectedItems(); + + GetScreen()->m_BlockLocate.SetState( STATE_NO_BLOCK ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_IDLE ); + GetScreen()->SetCurItem( NULL ); + m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString, + false ); + m_canvas->Refresh( true ); + } + + return nextCmd; +} + + +void LIB_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) +{ + wxPoint pt; + + if( !m_canvas->IsMouseCaptured() ) + { + DisplayError( this, wxT( "HandleBlockPLace : m_mouseCaptureCallback = NULL" ) ); + } + + GetScreen()->m_BlockLocate.SetState( STATE_BLOCK_STOP ); + + switch( GetScreen()->m_BlockLocate.GetCommand() ) + { + case BLOCK_IDLE: + break; + + case BLOCK_DRAG: // Drag + case BLOCK_DRAG_ITEM: + case BLOCK_MOVE: // Move + case BLOCK_PRESELECT_MOVE: // Move with preselection list + GetScreen()->m_BlockLocate.ClearItemsList(); + + if( GetCurPart() ) + SaveCopyInUndoList( GetCurPart() ); + + pt = GetScreen()->m_BlockLocate.GetMoveVector(); + pt.y *= -1; + + if( GetCurPart() ) + GetCurPart()->MoveSelectedItems( pt ); + + m_canvas->Refresh( true ); + break; + + case BLOCK_COPY: // Copy + GetScreen()->m_BlockLocate.ClearItemsList(); + + if( GetCurPart() ) + SaveCopyInUndoList( GetCurPart() ); + + pt = GetScreen()->m_BlockLocate.GetMoveVector(); + pt.y = -pt.y; + + if( GetCurPart() ) + GetCurPart()->CopySelectedItems( pt ); + + break; + + case BLOCK_PASTE: // Paste (recopy the last block saved) + GetScreen()->m_BlockLocate.ClearItemsList(); + break; + + case BLOCK_ROTATE: // Invert by popup menu, from block move + case BLOCK_MIRROR_X: // Invert by popup menu, from block move + case BLOCK_MIRROR_Y: // Invert by popup menu, from block move + if( GetCurPart() ) + SaveCopyInUndoList( GetCurPart() ); + + pt = GetScreen()->m_BlockLocate.Centre(); + pt = GetNearestGridPosition( pt ); + pt.y = -pt.y; + + if( GetCurPart() ) + { + int block_cmd = GetScreen()->m_BlockLocate.GetCommand(); + + if( block_cmd == BLOCK_MIRROR_Y) + GetCurPart()->MirrorSelectedItemsH( pt ); + else if( block_cmd == BLOCK_MIRROR_X) + GetCurPart()->MirrorSelectedItemsV( pt ); + else if( block_cmd == BLOCK_ROTATE ) + GetCurPart()->RotateSelectedItems( pt ); + } + + break; + + case BLOCK_ZOOM: // Handled by HandleBlockEnd + case BLOCK_DELETE: + case BLOCK_SAVE: + case BLOCK_ABORT: + default: + break; + } + + OnModify(); + + GetScreen()->m_BlockLocate.SetState( STATE_NO_BLOCK ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_IDLE ); + GetScreen()->SetCurItem( NULL ); + m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString, false ); + m_canvas->Refresh( true ); +} + + +/* + * Traces the outline of the search block structures + * The entire block follows the cursor + */ +void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + BLOCK_SELECTOR* block; + BASE_SCREEN* screen = aPanel->GetScreen(); + block = &screen->m_BlockLocate; + + LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) aPanel->GetParent(); + wxASSERT( parent != NULL ); + + LIB_PART* component = parent->GetCurPart(); + + if( component == NULL ) + return; + + int unit = parent->GetUnit(); + int convert = parent->GetConvert(); + + if( aErase ) + { + block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() ); + + component->Draw( aPanel, aDC, block->GetMoveVector(), unit, convert, + g_XorMode, UNSPECIFIED_COLOR, DefaultTransform, true, true, true ); + } + + // Repaint new view + block->SetMoveVector( parent->GetCrossHairPosition() - block->GetLastCursorPosition() ); + + GRSetDrawMode( aDC, g_XorMode ); + block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() ); + + component->Draw( aPanel, aDC, block->GetMoveVector(), unit, convert, + g_XorMode, UNSPECIFIED_COLOR, DefaultTransform, true, true, true ); +} diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp new file mode 100644 index 00000000..18e3bd13 --- /dev/null +++ b/eeschema/bus-wire-junction.cpp @@ -0,0 +1,505 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file bus-wire-junction.cpp + * @brief Code for editing buses, wires, and junctions. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC ); +static void ComputeBreakPoint( SCH_LINE* segment, const wxPoint& new_pos ); + +static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires, + // stores here the new wires. + + +/** + * In a contiguous list of wires, remove wires that backtrack over the previous + * wire. Example: + * + * Wire is added: + * ----------------------------------------> + * + * A second wire backtracks over it: + * -------------------<====================> + * + * RemoveBacktracks is called: + * -------------------> + */ +static void RemoveBacktracks( DLIST& aWires ) +{ + SCH_LINE* last_line = NULL; + + EDA_ITEM* first = aWires.GetFirst(); + for( EDA_ITEM* p = first; p; ) + { + SCH_LINE *line = dynamic_cast( p ); + if( !line ) + { + wxFAIL_MSG( "RemoveBacktracks() requires SCH_LINE items" ); + break; + } + p = line->Next(); + + if( last_line ) + { + wxASSERT_MSG( last_line->GetEndPoint() == line->GetStartPoint(), + "RemoveBacktracks() requires contiguous lines" ); + if( IsPointOnSegment( last_line->GetStartPoint(), line->GetStartPoint(), + line->GetEndPoint() ) ) + { + last_line->SetEndPoint( line->GetEndPoint() ); + delete s_wires.Remove( line ); + } + else + last_line = line; + } + else + last_line = line; + } +} + + +/** + * Mouse capture callback for drawing line segments. + */ +static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + SCH_LINE* segment; + + if( s_wires.GetCount() == 0 ) + return; + + segment = (SCH_LINE*) s_wires.begin(); + EDA_COLOR_T color = GetLayerColor( segment->GetLayer() ); + ColorChangeHighlightFlag( &color, !(color & HIGHLIGHT_FLAG) ); + + if( aErase ) + { + while( segment ) + { + if( !segment->IsNull() ) // Redraw if segment length != 0 + segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color ); + + segment = segment->Next(); + } + } + + SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent(); + + wxPoint endpos = frame->GetCrossHairPosition(); + + if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */ + ComputeBreakPoint( (SCH_LINE*) s_wires.GetLast()->Back(), endpos ); + else + ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos ); + + segment = (SCH_LINE*) s_wires.begin(); + + while( segment ) + { + if( !segment->IsNull() ) // Redraw if segment length != 0 + segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color ); + + segment = segment->Next(); + } +} + + +void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type ) +{ + SCH_LINE* segment; + SCH_LINE* nextSegment; + wxPoint cursorpos = GetCrossHairPosition(); + + // We should know if a segment is currently in progress + segment = (SCH_LINE*) GetScreen()->GetCurItem(); + if( segment ) // a current item exists, but not necessary a currently edited item + { + if( !segment->GetFlags() || ( segment->Type() != SCH_LINE_T ) ) + { + if( segment->GetFlags() ) + { + wxLogDebug( wxT( "BeginSegment: item->GetFlags()== %X" ), + segment->GetFlags() ); + } + // no wire, bus or graphic line in progress + segment = NULL; + } + } + + if( !segment ) // first point : Create the first wire or bus segment + { + switch( type ) + { + default: + segment = new SCH_LINE( cursorpos, LAYER_NOTES ); + break; + + case LAYER_WIRE: + segment = new SCH_LINE( cursorpos, LAYER_WIRE ); + + /* A junction will be created later, when we'll know the + * segment end position, and if the junction is really needed */ + break; + + case LAYER_BUS: + segment = new SCH_LINE( cursorpos, LAYER_BUS ); + break; + } + + segment->SetFlags( IS_NEW ); + s_wires.PushBack( segment ); + GetScreen()->SetCurItem( segment ); + + // We need 2 segments to go from a given start pin to an end point when the horizontal + // and vertical lines only switch is on. + if( GetForceHVLines() ) + { + nextSegment = new SCH_LINE( *segment ); + nextSegment->SetFlags( IS_NEW ); + s_wires.PushBack( nextSegment ); + GetScreen()->SetCurItem( nextSegment ); + } + + m_canvas->SetMouseCapture( DrawSegment, AbortCreateNewLine ); + SetRepeatItem( NULL ); + } + else // A segment is in progress: terminates the current segment and add a new segment. + { + SCH_LINE* prevSegment = segment->Back(); + + // Be aware prevSegment can be null when the horizontal and vertical lines only switch is off + // when we create the first segment. + + if( !GetForceHVLines() ) + { + // If only one segment is needed and it has a zero length, do not create a new one. + if( segment->IsNull() ) + return; + } + else + { + wxCHECK_RET( prevSegment != NULL, wxT( "Failed to create second line segment." ) ); + + // If two segments are required and they both have zero length, do not + // create a new one. + if( prevSegment && prevSegment->IsNull() && segment->IsNull() ) + return; + } + + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + // Terminate the command if the end point is on a pin, junction, or another wire or bus. + if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) ) + { + EndSegment( DC ); + return; + } + + // Create a new segment, and chain it after the current new segment. + nextSegment = new SCH_LINE( *segment ); + nextSegment->SetStartPoint( cursorpos ); + s_wires.PushBack( nextSegment ); + + segment->SetEndPoint( cursorpos ); + segment->ClearFlags( IS_NEW ); + segment->SetFlags( SELECTED ); + nextSegment->SetFlags( IS_NEW ); + GetScreen()->SetCurItem( nextSegment ); + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + } +} + + +void SCH_EDIT_FRAME::EndSegment( wxDC* DC ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem(); + + if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() ) + return; + + // Delete zero length segments and clear item flags. + SCH_ITEM* item = s_wires.begin(); + + while( item ) + { + item->ClearFlags(); + + wxCHECK_RET( item->Type() == SCH_LINE_T, wxT( "Unexpected object type in wire list." ) ); + + segment = (SCH_LINE*) item; + item = item->Next(); + + if( segment->IsNull() ) + delete s_wires.Remove( segment ); + } + + if( s_wires.GetCount() == 0 ) + return; + + // Get the last non-null wire (this is the last created segment). + SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() ); + + screen->SetCurItem( NULL ); + m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false ); + + // store the terminal point of this last segment: a junction could be needed + // (the last wire could be merged/deleted/modified, and lost) + wxPoint endpoint = segment->GetEndPoint(); + + // store the starting point of this first segment: a junction could be needed + SCH_LINE* firstsegment = (SCH_LINE*) s_wires.GetFirst(); + wxPoint startPoint = firstsegment->GetStartPoint(); + + // Save the old wires for the undo command + DLIST< SCH_ITEM > oldWires; // stores here the old wires + GetScreen()->ExtractWires( oldWires, true ); // Save them in oldWires list + // Put the snap shot of the previous wire, buses, and junctions in the undo/redo list. + PICKED_ITEMS_LIST oldItems; + oldItems.m_Status = UR_WIRE_IMAGE; + + while( oldWires.GetCount() != 0 ) + { + ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE ); + oldItems.PushItem( picker ); + } + + SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE ); + + // Remove segments backtracking over others + RemoveBacktracks( s_wires ); + + // Add the new wires + screen->Append( s_wires ); + + // Correct and remove segments that need to be merged. + screen->SchematicCleanUp( NULL, DC ); + + // A junction could be needed to connect the end point of the last created segment. + if( screen->IsJunctionNeeded( endpoint ) ) + screen->Append( AddJunction( DC, endpoint ) ); + + // A junction could be needed to connect the start point of the set of new created wires + if( screen->IsJunctionNeeded( startPoint ) ) + screen->Append( AddJunction( DC, startPoint ) ); + + m_canvas->Refresh(); + + OnModify(); +} + + +/** + * Function ComputeBreakPoint + * computes the middle coordinate for 2 segments from the start point to \a aPosition + * with the segments kept in the horizontal or vertical axis only. + * + * @param aSegment A pointer to a #SCH_LINE object containing the first line break point + * to compute. + * @param aPosition A reference to a wxPoint object containing the coordinates of the + * position used to calculate the line break point. + */ +static void ComputeBreakPoint( SCH_LINE* aSegment, const wxPoint& aPosition ) +{ + wxCHECK_RET( aSegment != NULL, wxT( "Cannot compute break point of NULL line segment." ) ); + + SCH_LINE* nextSegment = aSegment->Next(); + wxPoint midPoint = aPosition; + + wxCHECK_RET( nextSegment != NULL, + wxT( "Cannot compute break point of NULL second line segment." ) ); + +#if 0 + if( ABS( midPoint.x - aSegment->GetStartPoint().x ) < + ABS( midPoint.y - aSegment->GetStartPoint().y ) ) + midPoint.x = aSegment->GetStartPoint().x; + else + midPoint.y = aSegment->GetStartPoint().y; +#else + int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x; + int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y; + + if( iDy != 0 ) // keep the first segment orientation (currently horizontal) + { + midPoint.x = aSegment->GetStartPoint().x; + } + else if( iDx != 0 ) // keep the first segment orientation (currently vertical) + { + midPoint.y = aSegment->GetStartPoint().y; + } + else + { + if( std::abs( midPoint.x - aSegment->GetStartPoint().x ) < + std::abs( midPoint.y - aSegment->GetStartPoint().y ) ) + midPoint.x = aSegment->GetStartPoint().x; + else + midPoint.y = aSegment->GetStartPoint().y; + } +#endif + + aSegment->SetEndPoint( midPoint ); + nextSegment->SetStartPoint( midPoint ); + nextSegment->SetEndPoint( aPosition ); +} + + +void SCH_EDIT_FRAME::DeleteCurrentSegment( wxDC* DC ) +{ + SCH_SCREEN* screen = GetScreen(); + + SetRepeatItem( NULL ); + + if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() ) + return; + + DrawSegment( m_canvas, DC, wxDefaultPosition, false ); + + screen->Remove( screen->GetCurItem() ); + m_canvas->SetMouseCaptureCallback( NULL ); + screen->SetCurItem( NULL ); +} + + +SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( wxDC* aDC, const wxPoint& aPosition, + bool aPutInUndoList ) +{ + SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition ); + + SetRepeatItem( junction ); + + m_canvas->CrossHairOff( aDC ); // Erase schematic cursor + junction->Draw( m_canvas, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + m_canvas->CrossHairOn( aDC ); // Display schematic cursor + + if( aPutInUndoList ) + { + GetScreen()->Append( junction ); + SaveCopyInUndoList( junction, UR_NEW ); + OnModify(); + } + + return junction; +} + + +SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( wxDC* aDC, const wxPoint& aPosition ) +{ + SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition ); + + SetRepeatItem( no_connect ); + GetScreen()->Append( no_connect ); + GetScreen()->SchematicCleanUp( m_canvas, aDC ); + OnModify(); + m_canvas->Refresh(); + SaveCopyInUndoList( no_connect, UR_NEW ); + return no_connect; +} + + +/* Abort function for wire, bus or line creation + */ +static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + + if( screen->GetCurItem() ) + { + s_wires.DeleteAll(); // Free the list, for a future usage + screen->SetCurItem( NULL ); + aPanel->Refresh(); + } + else + { + SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent(); + parent->SetRepeatItem( NULL ); + } + + // Clear flags used in edit functions. + screen->ClearDrawingState(); +} + + +void SCH_EDIT_FRAME::RepeatDrawItem( wxDC* DC ) +{ + SCH_ITEM* repeater = GetRepeatItem(); + + if( !repeater ) + return; + + //D( repeater>Show( 0, std::cout ); ) + + // clone the repeater, move it, insert into display list, then save a copy + // via SetRepeatItem(); + + SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone(); + + // If cloning a component then put into 'move' mode. + if( my_clone->Type() == SCH_COMPONENT_T ) + { + wxPoint pos = GetCrossHairPosition() - + ( (SCH_COMPONENT*) my_clone )->GetPosition(); + + my_clone->SetFlags( IS_NEW ); + ( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() ); + my_clone->Move( pos ); + my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( my_clone, DC ); + } + else + { + my_clone->Move( GetRepeatStep() ); + + if( my_clone->CanIncrementLabel() ) + ( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() ); + + GetScreen()->Append( my_clone ); + GetScreen()->TestDanglingEnds(); + my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + SaveCopyInUndoList( my_clone, UR_NEW ); + my_clone->ClearFlags(); + } + + // clone my_clone, now that it has been moved, thus saving new position. + SetRepeatItem( my_clone ); +} diff --git a/eeschema/busentry.cpp b/eeschema/busentry.cpp new file mode 100644 index 00000000..06c3ba39 --- /dev/null +++ b/eeschema/busentry.cpp @@ -0,0 +1,83 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file busentry.cpp + * @brief Code to handle manipulation of bus entry objects. + */ + +#include +#include +#include +#include + +#include + + +static int s_LastShape = '\\'; + + +SCH_BUS_BUS_ENTRY* SCH_EDIT_FRAME::CreateBusBusEntry() +{ + // Create and place a new bus entry at cursor position + SCH_BUS_BUS_ENTRY* busEntry = new SCH_BUS_BUS_ENTRY( GetCrossHairPosition(), s_LastShape ); + + busEntry->SetFlags( IS_NEW ); + GetScreen()->SetCurItem( busEntry ); + addCurrentItemToList(); + return busEntry; +} + +SCH_BUS_WIRE_ENTRY* SCH_EDIT_FRAME::CreateBusWireEntry() +{ + // Create and place a new bus entry at cursor position + SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( GetCrossHairPosition(), s_LastShape ); + + busEntry->SetFlags( IS_NEW ); + GetScreen()->SetCurItem( busEntry ); + addCurrentItemToList(); + return busEntry; +} + +/* set the shape of BusEntry (shape = / or \ ) + */ +void SCH_EDIT_FRAME::SetBusEntryShape( wxDC* DC, SCH_BUS_ENTRY_BASE* BusEntry, char entry_shape ) +{ + if( BusEntry == NULL ) + return; + + /* Put old item in undo list if it is not currently in edit */ + if( BusEntry->GetFlags() == 0 ) + SaveCopyInUndoList( BusEntry, UR_CHANGED ); + + s_LastShape = entry_shape == '/' ? '/' : '\\'; + + BusEntry->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode ); + BusEntry->SetBusEntryShape( s_LastShape ); + GetScreen()->TestDanglingEnds(); + BusEntry->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode ); + + OnModify( ); +} diff --git a/eeschema/class_drc_erc_item.cpp b/eeschema/class_drc_erc_item.cpp new file mode 100644 index 00000000..9071dc89 --- /dev/null +++ b/eeschema/class_drc_erc_item.cpp @@ -0,0 +1,68 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 KiCad Developers, see change_log.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 + */ + + +/******************************************************************/ +/* class_drc_erc_item.cpp - DRC_ITEM class functions for eeschema */ +/******************************************************************/ +#include +#include + +#include +#include +#include + +wxString DRC_ITEM::GetErrorText() const +{ + switch( m_ErrorCode ) + { + case ERCE_UNSPECIFIED: + return wxString( _("ERC err unspecified") ); + case ERCE_DUPLICATE_SHEET_NAME: + return wxString( _("Duplicate sheet names within a given sheet") ); + case ERCE_PIN_NOT_CONNECTED: + return wxString( _("Pin not connected (and no connect symbol found on this pin)") ); + case ERCE_PIN_NOT_DRIVEN: + return wxString( _("Pin connected to some others pins but no pin to drive it") ); + case ERCE_PIN_TO_PIN_WARNING: + return wxString( _("Conflict problem between pins. Severity: warning") ); + case ERCE_PIN_TO_PIN_ERROR: + return wxString( _("Conflict problem between pins. Severity: error") ); + case ERCE_HIERACHICAL_LABEL: + return wxString( _("Mismatch between hierarchical labels and pins sheets")); + case ERCE_NOCONNECT_CONNECTED: + return wxString( _("A no connect symbol is connected to more than 1 pin")); + case ERCE_GLOBLABEL: + return wxString( _("Global label not connected to any other global label") ); + + default: + return wxString( wxT("Unkown.") ); + } +} + +wxString DRC_ITEM::ShowCoord( const wxPoint& aPos ) +{ + wxString ret; + ret << aPos; + return ret; +} diff --git a/eeschema/class_libentry.cpp b/eeschema/class_libentry.cpp new file mode 100644 index 00000000..cb99d686 --- /dev/null +++ b/eeschema/class_libentry.cpp @@ -0,0 +1,1898 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_libentry.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// the separator char between the subpart id and the reference +// 0 (no separator) or '.' or some other character +int LIB_PART::m_subpartIdSeparator = 0; + +// the ascii char value to calculate the subpart symbol id from the part number: +// 'A' or '1' usually. (to print U1.A or U1.1) +// if this a a digit, a number is used as id symbol +int LIB_PART::m_subpartFirstId = 'A'; + + +const wxChar traceSchLibMem[] = wxT( "KISCHLIBMEM" ); // public + + +LIB_ALIAS::LIB_ALIAS( const wxString& aName, LIB_PART* aRootPart ): + EDA_ITEM( LIB_ALIAS_T ), + shared( aRootPart ) +{ + name = aName; +} + + +LIB_ALIAS::LIB_ALIAS( const LIB_ALIAS& aAlias, LIB_PART* aRootPart ) : + EDA_ITEM( aAlias ), + shared( aRootPart ) +{ + name = aAlias.name; + + description = aAlias.description; + keyWords = aAlias.keyWords; + docFileName = aAlias.docFileName; +} + + +LIB_ALIAS::~LIB_ALIAS() +{ + wxASSERT_MSG( shared, wxT( "~LIB_ALIAS() without a LIB_PART" ) ); + + wxLogTrace( traceSchLibMem, + wxT( "%s: destroying alias:'%s' of part:'%s'." ), + GetChars( wxString::FromAscii( __WXFUNCTION__ ) ), GetChars( name ), + GetChars( shared->GetName() ) ); + + if( shared ) + shared->RemoveAlias( this ); +} + + +const wxString LIB_ALIAS::GetLibraryName() +{ + wxASSERT_MSG( shared, wxT( "LIB_ALIAS without a LIB_PART" ) ); + + if( shared ) + return shared->GetLibraryName(); + + return wxString( _( "none" ) ); +} + + +bool LIB_ALIAS::IsRoot() const +{ + return Cmp_KEEPCASE( name, shared->GetName() ) == 0; +} + + +PART_LIB* LIB_ALIAS::GetLib() +{ + return shared->GetLib(); +} + + +bool LIB_ALIAS::SaveDoc( OUTPUTFORMATTER& aFormatter ) +{ + if( description.IsEmpty() && keyWords.IsEmpty() && docFileName.IsEmpty() ) + return true; + + try + { + aFormatter.Print( 0, "#\n$CMP %s\n", TO_UTF8( name ) ); + + if( !description.IsEmpty() ) + aFormatter.Print( 0, "D %s\n", TO_UTF8( description ) ); + + if( !keyWords.IsEmpty() ) + aFormatter.Print( 0, "K %s\n", TO_UTF8( keyWords ) ); + + if( !docFileName.IsEmpty() ) + aFormatter.Print( 0, "F %s\n", TO_UTF8( docFileName ) ); + + aFormatter.Print( 0, "$ENDCMP\n" ); + } + catch( const IO_ERROR& ioe ) + { + return false; + } + + return true; +} + + +bool LIB_ALIAS::operator==( const wxChar* aName ) const +{ + return Cmp_KEEPCASE( name, aName ) == 0; +} + + +bool operator<( const LIB_ALIAS& aItem1, const LIB_ALIAS& aItem2 ) +{ + return Cmp_KEEPCASE( aItem1.GetName(), aItem2.GetName() ) < 0; +} + + +int LibraryEntryCompare( const LIB_ALIAS* aItem1, const LIB_ALIAS* aItem2 ) +{ + return Cmp_KEEPCASE( aItem1->GetName(), aItem2->GetName() ); +} + + +/// http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared +struct null_deleter +{ + void operator()(void const *) const + { + } +}; + + +LIB_PART::LIB_PART( const wxString& aName, PART_LIB* aLibrary ) : + EDA_ITEM( LIB_PART_T ), + m_me( this, null_deleter() ) +{ + m_name = aName; + m_library = aLibrary; + m_dateModified = 0; + m_unitCount = 1; + m_pinNameOffset = 40; + m_options = ENTRY_NORMAL; + m_unitsLocked = false; + m_showPinNumbers = true; + m_showPinNames = true; + + // Create the default alias if the name parameter is not empty. + if( !aName.IsEmpty() ) + m_aliases.push_back( new LIB_ALIAS( aName, this ) ); + + // Add the MANDATORY_FIELDS in RAM only. These are assumed to be present + // when the field editors are invoked. + LIB_FIELD* value = new LIB_FIELD( this, VALUE ); + value->SetText( aName ); + drawings.push_back( value ); + + drawings.push_back( new LIB_FIELD( this, REFERENCE ) ); + drawings.push_back( new LIB_FIELD( this, FOOTPRINT ) ); + drawings.push_back( new LIB_FIELD( this, DATASHEET ) ); +} + + +LIB_PART::LIB_PART( LIB_PART& aPart, PART_LIB* aLibrary ) : + EDA_ITEM( aPart ), + m_me( this, null_deleter() ) +{ + LIB_ITEM* newItem; + + m_library = aLibrary; + m_name = aPart.m_name; + m_FootprintList = aPart.m_FootprintList; + m_unitCount = aPart.m_unitCount; + m_unitsLocked = aPart.m_unitsLocked; + m_pinNameOffset = aPart.m_pinNameOffset; + m_showPinNumbers = aPart.m_showPinNumbers; + m_showPinNames = aPart.m_showPinNames; + m_dateModified = aPart.m_dateModified; + m_options = aPart.m_options; + + BOOST_FOREACH( LIB_ITEM& oldItem, aPart.GetDrawItemList() ) + { + if( oldItem.IsNew() ) + continue; + + newItem = (LIB_ITEM*) oldItem.Clone(); + newItem->SetParent( this ); + drawings.push_back( newItem ); + } + + for( size_t i = 0; i < aPart.m_aliases.size(); i++ ) + { + LIB_ALIAS* alias = new LIB_ALIAS( *aPart.m_aliases[i], this ); + m_aliases.push_back( alias ); + } +} + + +LIB_PART::~LIB_PART() +{ + wxLogTrace( traceSchLibMem, + wxT( "%s: destroying part '%s' with alias list count of %llu." ), + GetChars( wxString::FromAscii( __WXFUNCTION__ ) ), GetChars( GetName() ), + (long long unsigned) m_aliases.size() ); + + // If the part is being deleted directly rather than through the library, + // delete all of the aliases. + while( m_aliases.size() ) + { + LIB_ALIAS* alias = m_aliases.back(); + m_aliases.pop_back(); + delete alias; + } +} + + +const wxString LIB_PART::GetLibraryName() +{ + if( m_library ) + return m_library->GetName(); + + return wxString( _( "none" ) ); +} + + +wxString LIB_PART::SubReference( int aUnit, bool aAddSeparator ) +{ + wxString subRef; + + if( m_subpartIdSeparator != 0 && aAddSeparator ) + subRef << wxChar( m_subpartIdSeparator ); + + if( m_subpartFirstId >= '0' && m_subpartFirstId <= '9' ) + subRef << aUnit; + else + { + // use letters as notation. To allow more than 26 units, the sub ref + // use one letter if letter = A .. Z or a ... z, and 2 letters otherwise + // first letter is expected to be 'A' or 'a' (i.e. 26 letters are available) + int u; + aUnit -= 1; // Unit number starts to 1. now to 0. + + while( aUnit >= 26 ) // more than one letter are needed + { + u = aUnit / 26; + subRef << wxChar( m_subpartFirstId + u -1 ); + aUnit %= 26; + } + + u = m_subpartFirstId + aUnit; + subRef << wxChar( u ); + } + + return subRef; +} + + +void LIB_PART::SetName( const wxString& aName ) +{ + m_name = aName; + GetValueField().SetText( aName ); + m_aliases[0]->SetName( aName ); +} + + +void LIB_PART::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDc, const wxPoint& aOffset, int aMulti, + int aConvert, GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor, + const TRANSFORM& aTransform, bool aShowPinText, bool aDrawFields, + bool aOnlySelected, const std::vector* aPinsDangling ) +{ + BASE_SCREEN* screen = aPanel ? aPanel->GetScreen() : NULL; + + GRSetDrawMode( aDc, aDrawMode ); + + /* draw background for filled items using background option + * Solid lines will be drawn after the background + * Note also, background is not drawn when: + * printing in black and white + * If the color is not the default color (aColor != -1 ) + */ + if( ! (screen && screen->m_IsPrinting && GetGRForceBlackPenState()) + && (aColor == UNSPECIFIED_COLOR) ) + { + BOOST_FOREACH( LIB_ITEM& drawItem, drawings ) + { + if( drawItem.m_Fill != FILLED_WITH_BG_BODYCOLOR ) + continue; + + if( aOnlySelected && !drawItem.IsSelected() ) + continue; + + // Do not draw an item while moving (the cursor handler does that) + if( drawItem.m_Flags & IS_MOVED ) + continue; + + // Do not draw items not attached to the current part + if( aMulti && drawItem.m_Unit && ( drawItem.m_Unit != aMulti ) ) + continue; + + if( aConvert && drawItem.m_Convert && ( drawItem.m_Convert != aConvert ) ) + continue; + + if( drawItem.Type() == LIB_FIELD_T ) + continue; + + if( drawItem.Type() == LIB_FIELD_T ) + { + drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) NULL, aTransform ); + } + + // Now, draw only the background for items with + // m_Fill == FILLED_WITH_BG_BODYCOLOR: + drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) false, aTransform ); + } + } + + // Track the index into the dangling pins list + size_t pin_index = 0; + + BOOST_FOREACH( LIB_ITEM& drawItem, drawings ) + { + if( aOnlySelected && !drawItem.IsSelected() ) + continue; + + // Do not draw an item while moving (the cursor handler does that) + if( drawItem.m_Flags & IS_MOVED ) + continue; + + // Do not draw items not attached to the current part + if( aMulti && drawItem.m_Unit && ( drawItem.m_Unit != aMulti ) ) + continue; + + if( aConvert && drawItem.m_Convert && ( drawItem.m_Convert != aConvert ) ) + continue; + + if( !aDrawFields && drawItem.Type() == LIB_FIELD_T ) + continue; + + if( drawItem.Type() == LIB_PIN_T ) + { + LIB_PIN& pin = dynamic_cast( drawItem ); + + uintptr_t flags = 0; + if( aShowPinText ) + flags |= PIN_DRAW_TEXTS; + + if( !aPinsDangling || (aPinsDangling->size() > pin_index && (*aPinsDangling)[pin_index] ) ) + flags |= PIN_DRAW_DANGLING; + + if( pin.IsPowerConnection() && IsPower() ) + flags |= PIN_DANGLING_HIDDEN; + + drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) flags, aTransform ); + + ++pin_index; + } + else if( drawItem.Type() == LIB_FIELD_T ) + { + drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) NULL, aTransform ); + } + else + { + bool forceNoFill = drawItem.m_Fill == FILLED_WITH_BG_BODYCOLOR; + drawItem.Draw( aPanel, aDc, aOffset, aColor, aDrawMode, (void*) forceNoFill, + aTransform ); + } + + } + + // Enable this to draw the anchor of the component. +#if 0 + int len = aDc->DeviceToLogicalXRel( 3 ); + EDA_RECT* const clipbox = aPanel ? aPanel->GetClipBox() : NULL; + + GRLine( clipbox, aDc, aOffset.x, aOffset.y - len, aOffset.x, + aOffset.y + len, 0, aColor ); + GRLine( clipbox, aDc, aOffset.x - len, aOffset.y, aOffset.x + len, + aOffset.y, 0, aColor ); +#endif + + /* Enable this to draw the bounding box around the component to validate + * the bounding box calculations. */ +#if 0 + EDA_RECT bBox = GetBoundingBox( aMulti, aConvert ); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( aPanel ? aPanel->GetClipBox() : NULL, aDc, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +void LIB_PART::Plot( PLOTTER* aPlotter, int aUnit, int aConvert, + const wxPoint& aOffset, const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + bool fill = aPlotter->GetColorMode(); + + // draw background for filled items using background option + // Solid lines will be drawn after the background + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + // Lib Fields are not plotted here, because this plot function + // is used to plot schematic items, which have they own fields + if( item.Type() == LIB_FIELD_T ) + continue; + + if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) ) + continue; + + if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) ) + continue; + + if( item.m_Fill == FILLED_WITH_BG_BODYCOLOR ) + item.Plot( aPlotter, aOffset, fill, aTransform ); + } + + // Not filled items and filled shapes are now plotted + // (plot only items which are not already plotted) + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() == LIB_FIELD_T ) + continue; + + if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) ) + continue; + + if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) ) + continue; + + if( item.m_Fill != FILLED_WITH_BG_BODYCOLOR ) + item.Plot( aPlotter, aOffset, fill, aTransform ); + } +} + +void LIB_PART::PlotLibFields( PLOTTER* aPlotter, int aUnit, int aConvert, + const wxPoint& aOffset, const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + aPlotter->SetColor( GetLayerColor( LAYER_FIELDS ) ); + bool fill = aPlotter->GetColorMode(); + + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() != LIB_FIELD_T ) + continue; + + if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) ) + continue; + + if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) ) + continue; + + // The reference is a special case: we should change the basic text + // to add '?' and the part id + LIB_FIELD& field = (LIB_FIELD&) item; + wxString tmp = field.GetShownText(); + if( field.GetId() == REFERENCE ) + { + wxString text = field.GetFullText( aUnit ); + field.SetText( text ); + } + item.Plot( aPlotter, aOffset, fill, aTransform ); + field.SetText( tmp ); + } +} + + +void LIB_PART::RemoveDrawItem( LIB_ITEM* aItem, EDA_DRAW_PANEL* aPanel, wxDC* aDc ) +{ + wxASSERT( aItem != NULL ); + + // none of the MANDATORY_FIELDS may be removed in RAM, but they may be + // omitted when saving to disk. + if( aItem->Type() == LIB_FIELD_T ) + { + LIB_FIELD* field = (LIB_FIELD*) aItem; + + if( field->GetId() < MANDATORY_FIELDS ) + { + wxLogWarning( _( + "An attempt was made to remove the %s field from component %s in library %s." ), + GetChars( field->GetName() ), GetChars( GetName() ), + GetChars( GetLibraryName() ) ); + return; + } + } + + LIB_ITEMS::iterator i; + + for( i = drawings.begin(); i < drawings.end(); i++ ) + { + if( *i == aItem ) + { + if( aDc != NULL ) + aItem->Draw( aPanel, aDc, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, + g_XorMode, NULL, DefaultTransform ); + + drawings.erase( i ); + SetModified(); + break; + } + } +} + + +void LIB_PART::AddDrawItem( LIB_ITEM* aItem ) +{ + wxASSERT( aItem != NULL ); + + drawings.push_back( aItem ); + drawings.sort(); +} + + +LIB_ITEM* LIB_PART::GetNextDrawItem( LIB_ITEM* aItem, KICAD_T aType ) +{ + /* Return the next draw object pointer. + * If item is NULL return the first item of type in the list. + */ + if( drawings.empty() ) + return NULL; + + if( aItem == NULL && aType == TYPE_NOT_INIT ) // type is unspecified + return &drawings[0]; + + // Search for last item + size_t idx = 0; + + if( aItem ) + { + for( ; idx < drawings.size(); idx++ ) + { + if( aItem == &drawings[idx] ) + { + idx++; // Prepare the next item search + break; + } + } + } + + // Search the next item + for( ; idx < drawings.size(); idx++ ) + { + if( aType == TYPE_NOT_INIT || drawings[ idx ].Type() == aType ) + return &drawings[ idx ]; + } + + return NULL; +} + + +void LIB_PART::GetPins( LIB_PINS& aList, int aUnit, int aConvert ) +{ + /* Notes: + * when aUnit == 0: no unit filtering + * when aConvert == 0: no convert (shape selection) filtering + * when .m_Unit == 0, the body item is common to units + * when .m_Convert == 0, the body item is common to shapes + */ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() != LIB_PIN_T ) // we search pins only + continue; + + // Unit filtering: + if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) ) + continue; + + // Shape filtering: + if( aConvert && item.m_Convert && ( item.m_Convert != aConvert ) ) + continue; + + aList.push_back( (LIB_PIN*) &item ); + } +} + + +LIB_PIN* LIB_PART::GetPin( const wxString& aNumber, int aUnit, int aConvert ) +{ + wxString pNumber; + LIB_PINS pinList; + + GetPins( pinList, aUnit, aConvert ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + wxASSERT( pinList[i]->Type() == LIB_PIN_T ); + + pinList[i]->PinStringNum( pNumber ); + + if( aNumber == pNumber ) + return pinList[i]; + } + + return NULL; +} + + +bool LIB_PART::PinsConflictWith( LIB_PART& aOtherPart, bool aTestNums, bool aTestNames, + bool aTestType, bool aTestOrientation, bool aTestLength ) +{ + LIB_PINS thisPinList; + GetPins( thisPinList, /* aUnit */ 0, /* aConvert */ 0 ); + + BOOST_FOREACH( LIB_PIN* eachThisPin, thisPinList ) + { + wxASSERT( eachThisPin ); + LIB_PINS otherPinList; + aOtherPart.GetPins( otherPinList, /* aUnit */ 0, /* aConvert */ 0 ); + bool foundMatch = false; + + BOOST_FOREACH( LIB_PIN* eachOtherPin, otherPinList ) + { + wxASSERT( eachOtherPin ); + // Same position? + if( eachThisPin->GetPosition() != eachOtherPin->GetPosition() ) + continue; + + // Same number? + wxString eachThisPinNumber, eachOtherPinNumber; + eachThisPin->PinStringNum( eachThisPinNumber ); + eachOtherPin->PinStringNum( eachOtherPinNumber ); + if( aTestNums && ( eachThisPinNumber != eachOtherPinNumber )) + continue; + + // Same name? + if( aTestNames && ( eachThisPin->GetName() != eachOtherPin->GetName() )) + continue; + + // Same electrical type? + if( aTestType && ( eachThisPin->GetType() != eachOtherPin->GetType() )) + continue; + + // Same orientation? + if( aTestOrientation && ( eachThisPin->GetOrientation() != eachOtherPin->GetOrientation() )) + continue; + + // Same length? + if( aTestLength && ( eachThisPin->GetLength() != eachOtherPin->GetLength() )) + continue; + + foundMatch = true; + } + + if( !foundMatch ) + { + // This means there was not an identical (according to the arguments) + // pin at the same position in the other component. + return true; + } + } + + // The loop never gave up, so no conflicts were found. + return false; +} + + +bool LIB_PART::Save( OUTPUTFORMATTER& aFormatter ) +{ + LIB_FIELD& value = GetValueField(); + + // First line: it s a comment (component name for readers) + aFormatter.Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) ); + + // Save data + aFormatter.Print( 0, "DEF" ); + +#if 0 && defined(DEBUG) + if( value.GetText() == wxT( "R" ) ) + { + int breakhere = 1; + (void) breakhere; + } +#endif + + if( value.IsVisible() ) + { + aFormatter.Print( 0, " %s", TO_UTF8( value.GetText() ) ); + } + else + { + aFormatter.Print( 0, " ~%s", TO_UTF8( value.GetText() ) ); + } + + LIB_FIELD& reference = GetReferenceField(); + + if( !reference.GetText().IsEmpty() ) + { + aFormatter.Print( 0, " %s", TO_UTF8( reference.GetText() ) ); + } + else + { + aFormatter.Print( 0, " ~" ); + } + + aFormatter.Print( 0, " %d %d %c %c %d %c %c\n", + 0, m_pinNameOffset, + m_showPinNumbers ? 'Y' : 'N', + m_showPinNames ? 'Y' : 'N', + m_unitCount, m_unitsLocked ? 'L' : 'F', + m_options == ENTRY_POWER ? 'P' : 'N' ); + + if( !SaveDateAndTime( aFormatter ) ) + return false; + + LIB_FIELDS fields; + GetFields( fields ); + + // Mandatory fields: + // may have their own save policy so there is a separate loop for them. + // Empty fields are saved, because the user may have set visibility, + // size and orientation + for( int i = 0; i < MANDATORY_FIELDS; ++i ) + { + if( !fields[i].Save( aFormatter ) ) + return false; + } + + // User defined fields: + // may have their own save policy so there is a separate loop for them. + + int fieldId = MANDATORY_FIELDS; // really wish this would go away. + + for( unsigned i = MANDATORY_FIELDS; i < fields.size(); ++i ) + { + // There is no need to save empty fields, i.e. no reason to preserve field + // names now that fields names come in dynamically through the template + // fieldnames. + if( !fields[i].GetText().IsEmpty() ) + { + fields[i].SetId( fieldId++ ); + + if( !fields[i].Save( aFormatter ) ) + return false; + } + } + + // Save the alias list: a line starting by "ALIAS". The first alias is the root + // and has the same name as the component. In the old library file format this + // alias does not get added to the alias list. + if( m_aliases.size() > 1 ) + { + aFormatter.Print( 0, "ALIAS" ); + + for( unsigned i = 1; i < m_aliases.size(); i++ ) + { + aFormatter.Print( 0, " %s", TO_UTF8( m_aliases[i]->GetName() ) ); + } + + aFormatter.Print( 0, "\n" ); + } + + // Write the footprint filter list + if( m_FootprintList.GetCount() != 0 ) + { + aFormatter.Print( 0, "$FPLIST\n" ); + + for( unsigned i = 0; i < m_FootprintList.GetCount(); i++ ) + { + aFormatter.Print( 0, " %s\n", TO_UTF8( m_FootprintList[i] ) ); + } + + aFormatter.Print( 0, "$ENDFPLIST\n" ); + } + + // Save graphics items (including pins) + if( !drawings.empty() ) + { + /* we sort the draw items, in order to have an edition more easy, + * when a file editing "by hand" is made */ + drawings.sort(); + + aFormatter.Print( 0, "DRAW\n" ); + + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() == LIB_FIELD_T ) + continue; + + if( !item.Save( aFormatter ) ) + return false; + } + + aFormatter.Print( 0, "ENDDRAW\n" ); + } + + aFormatter.Print( 0, "ENDDEF\n" ); + + return true; +} + + +bool LIB_PART::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + int unused; + char* p; + char* componentName; + char* prefix = NULL; + char* line; + + bool result; + wxString Msg; + + line = aLineReader.Line(); + + p = strtok( line, " \t\r\n" ); + + if( strcmp( p, "DEF" ) != 0 ) + { + aErrorMsg.Printf( wxT( "DEF command expected in line %d, aborted." ), + aLineReader.LineNumber() ); + return false; + } + + // Read DEF line: + char drawnum = 0; + char drawname = 0; + + if( ( componentName = strtok( NULL, " \t\n" ) ) == NULL // Part name: + || ( prefix = strtok( NULL, " \t\n" ) ) == NULL // Prefix name: + || ( p = strtok( NULL, " \t\n" ) ) == NULL // NumOfPins: + || sscanf( p, "%d", &unused ) != 1 + || ( p = strtok( NULL, " \t\n" ) ) == NULL // TextInside: + || sscanf( p, "%d", &m_pinNameOffset ) != 1 + || ( p = strtok( NULL, " \t\n" ) ) == NULL // DrawNums: + || sscanf( p, "%c", &drawnum ) != 1 + || ( p = strtok( NULL, " \t\n" ) ) == NULL // DrawNums: + || sscanf( p, "%c", &drawname ) != 1 + || ( p = strtok( NULL, " \t\n" ) ) == NULL // m_unitCount: + || sscanf( p, "%d", &m_unitCount ) != 1 ) + { + aErrorMsg.Printf( wxT( "Wrong DEF format in line %d, skipped." ), + aLineReader.LineNumber() ); + + while( (line = aLineReader.ReadLine()) != NULL ) + { + p = strtok( line, " \t\n" ); + + if( p && stricmp( p, "ENDDEF" ) == 0 ) + break; + } + + return false; + } + + // Ensure m_unitCount is >= 1 (could be read as 0 in old libraries) + if( m_unitCount < 1 ) + m_unitCount = 1; + + m_showPinNumbers = ( drawnum == 'N' ) ? false : true; + m_showPinNames = ( drawname == 'N' ) ? false : true; + + // Copy part name and prefix. + LIB_FIELD& value = GetValueField(); + + if( componentName[0] != '~' ) + { + m_name = FROM_UTF8( componentName ); + value.SetText( m_name ); + } + else + { + m_name = FROM_UTF8( &componentName[1] ); + value.SetText( m_name ); + value.SetVisible( false ); + } + + // Add the root alias to the alias list. + m_aliases.push_back( new LIB_ALIAS( m_name, this ) ); + + LIB_FIELD& reference = GetReferenceField(); + + if( strcmp( prefix, "~" ) == 0 ) + { + reference.Empty(); + reference.SetVisible( false ); + } + else + { + reference.SetText( FROM_UTF8( prefix ) ); + } + + // Copy optional infos + if( ( p = strtok( NULL, " \t\n" ) ) != NULL && *p == 'L' ) + m_unitsLocked = true; + + if( ( p = strtok( NULL, " \t\n" ) ) != NULL && *p == 'P' ) + m_options = ENTRY_POWER; + + // Read next lines, until "ENDDEF" is found + while( ( line = aLineReader.ReadLine() ) != NULL ) + { + p = strtok( line, " \t\r\n" ); + + // This is the error flag ( if an error occurs, result = false) + result = true; + + if( *line == '#' ) // a comment + continue; + + if( p == NULL ) // empty line + continue; + + if( line[0] == 'T' && line[1] == 'i' ) + result = LoadDateAndTime( aLineReader ); + else if( *line == 'F' ) + result = LoadField( aLineReader, Msg ); + else if( strcmp( p, "ENDDEF" ) == 0 ) // End of component description + goto ok; + else if( strcmp( p, "DRAW" ) == 0 ) + result = LoadDrawEntries( aLineReader, Msg ); + else if( strncmp( p, "ALIAS", 5 ) == 0 ) + { + p = strtok( NULL, "\r\n" ); + result = LoadAliases( p, aErrorMsg ); + } + else if( strncmp( p, "$FPLIST", 5 ) == 0 ) + result = LoadFootprints( aLineReader, Msg ); + + // End line or block analysis: test for an error + if( !result ) + { + if( Msg.IsEmpty() ) + aErrorMsg.Printf( wxT( "error occurred at line %d " ), aLineReader.LineNumber() ); + else + aErrorMsg.Printf( wxT( "error <%s> occurred at line %d " ), + GetChars( Msg ), aLineReader.LineNumber() ); + + return false; + } + } + + return false; + +ok: + // If we are here, this part is O.k. - put it in: + drawings.sort(); + + return true; +} + + +bool LIB_PART::LoadDrawEntries( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char* line; + LIB_ITEM* newEntry = NULL; + + while( true ) + { + if( !( line = aLineReader.ReadLine() ) ) + { + aErrorMsg = wxT( "file ended prematurely loading component draw element" ); + return false; + } + + if( strncmp( line, "ENDDRAW", 7 ) == 0 ) + break; + + newEntry = NULL; + + switch( line[0] ) + { + case 'A': // Arc + newEntry = ( LIB_ITEM* ) new LIB_ARC( this ); + break; + + case 'C': // Circle + newEntry = ( LIB_ITEM* ) new LIB_CIRCLE( this ); + break; + + case 'T': // Text + newEntry = ( LIB_ITEM* ) new LIB_TEXT( this ); + break; + + case 'S': // Square + newEntry = ( LIB_ITEM* ) new LIB_RECTANGLE( this ); + break; + + case 'X': // Pin Description + newEntry = ( LIB_ITEM* ) new LIB_PIN( this ); + break; + + case 'P': // Polyline + newEntry = ( LIB_ITEM* ) new LIB_POLYLINE( this ); + break; + + case 'B': // Bezier Curves + newEntry = ( LIB_ITEM* ) new LIB_BEZIER( this ); + break; + + case '#': // Comment + continue; + + case '\n': + case '\r': + case 0: // empty line + continue; + + default: + aErrorMsg.Printf( wxT( "undefined DRAW command %c" ), line[0] ); + return false; + } + + if( !newEntry->Load( aLineReader, aErrorMsg ) ) + { + aErrorMsg.Printf( wxT( "error '%s' in DRAW command %c" ), + GetChars( aErrorMsg ), line[0] ); + delete newEntry; + + // Flush till end of draw section + do + { + if( !aLineReader.ReadLine() ) + { + aErrorMsg = wxT( "file ended prematurely while attempting " + "to flush to end of drawing section." ); + return false; + } + } while( strncmp( line, "ENDDRAW", 7 ) != 0 ); + + return false; + } + else + { + drawings.push_back( newEntry ); + } + } + + return true; +} + + +bool LIB_PART::LoadAliases( char* aLine, wxString& aErrorMsg ) +{ + char* text = strtok( aLine, " \t\r\n" ); + + while( text ) + { + m_aliases.push_back( new LIB_ALIAS( FROM_UTF8( text ), this ) ); + text = strtok( NULL, " \t\r\n" ); + } + + return true; +} + + +bool LIB_PART::LoadField( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + LIB_FIELD* field = new LIB_FIELD( this ); + + if( !field->Load( aLineReader, aErrorMsg ) ) + { + delete field; + return false; + } + + if( field->GetId() < MANDATORY_FIELDS ) + { + LIB_FIELD* fixedField = GetField( field->GetId() ); + + // this will fire only if somebody broke a constructor or editor. + // MANDATORY_FIELDS are always present in ram resident components, no + // exceptions, and they always have their names set, even fixed fields. + wxASSERT( fixedField ); + + *fixedField = *field; + + if( field->GetId() == VALUE ) + m_name = field->GetText(); + + delete field; + } + else + { + drawings.push_back( field ); + } + + return true; +} + + +bool LIB_PART::LoadFootprints( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char* line; + char* p; + + while( true ) + { + if( !( line = aLineReader.ReadLine() ) ) + { + aErrorMsg = wxT( "file ended prematurely while loading footprints" ); + return false; + } + + p = strtok( line, " \t\r\n" ); + + if( stricmp( p, "$ENDFPLIST" ) == 0 ) + break; + + m_FootprintList.Add( FROM_UTF8( p ) ); + } + + return true; +} + + +const EDA_RECT LIB_PART::GetBoundingBox( int aUnit, int aConvert ) const +{ + EDA_RECT bBox; + bool initialized = false; + + for( unsigned ii = 0; ii < drawings.size(); ii++ ) + { + const LIB_ITEM& item = drawings[ii]; + + if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 ) + && ( aUnit != item.m_Unit ) ) ) + continue; + + if( item.m_Convert > 0 && ( ( aConvert > 0 ) && ( aConvert != item.m_Convert ) ) ) + continue; + + if ( ( item.Type() == LIB_FIELD_T ) && !( ( LIB_FIELD& ) item ).IsVisible() ) + continue; + + if( initialized ) + bBox.Merge( item.GetBoundingBox() ); + else + { + bBox = item.GetBoundingBox(); + initialized = true; + } + } + + return bBox; +} + + +const EDA_RECT LIB_PART::GetBodyBoundingBox( int aUnit, int aConvert ) const +{ + EDA_RECT bBox; + bool initialized = false; + + for( unsigned ii = 0; ii < drawings.size(); ii++ ) + { + const LIB_ITEM& item = drawings[ii]; + + if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 ) + && ( aUnit != item.m_Unit ) ) ) + continue; + + if( item.m_Convert > 0 && ( ( aConvert > 0 ) && ( aConvert != item.m_Convert ) ) ) + continue; + + if ( item.Type() == LIB_FIELD_T ) + continue; + + if( initialized ) + bBox.Merge( item.GetBoundingBox() ); + else + { + bBox = item.GetBoundingBox(); + initialized = true; + } + } + + return bBox; +} + + +void LIB_PART::deleteAllFields() +{ + LIB_ITEMS::iterator it; + + for( it = drawings.begin(); it!=drawings.end(); /* deleting */ ) + { + if( it->Type() != LIB_FIELD_T ) + { + ++it; + continue; + } + + // 'it' is not advanced, but should point to next in list after erase() + it = drawings.erase( it ); + } +} + + +void LIB_PART::SetFields( const std::vector & aFields ) +{ + deleteAllFields(); + + for( unsigned i=0; iSetParent( this ); + drawings.push_back( field ); + } + + // Reorder drawings: transparent polygons first, pins and text last. + // so texts have priority on screen. + drawings.sort(); +} + + +void LIB_PART::GetFields( LIB_FIELDS& aList ) +{ + LIB_FIELD* field; + + // The only caller of this function is the library field editor, so it + // establishes policy here. + + // Grab the MANDATORY_FIELDS first, in expected order given by + // enum NumFieldType + for( int id=0; idGetId() < MANDATORY_FIELDS ) + continue; // was added above + + aList.push_back( *field ); + } +} + + +LIB_FIELD* LIB_PART::GetField( int aId ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() != LIB_FIELD_T ) + continue; + + LIB_FIELD* field = ( LIB_FIELD* ) &item; + + if( field->GetId() == aId ) + return field; + } + + return NULL; +} + + +LIB_FIELD* LIB_PART::FindField( const wxString& aFieldName ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( item.Type() != LIB_FIELD_T ) + continue; + + LIB_FIELD* field = ( LIB_FIELD* ) &item; + + if( field->GetName() == aFieldName ) + return field; + } + + return NULL; +} + + +LIB_FIELD& LIB_PART::GetValueField() +{ + LIB_FIELD* field = GetField( VALUE ); + wxASSERT( field != NULL ); + return *field; +} + + +LIB_FIELD& LIB_PART::GetReferenceField() +{ + LIB_FIELD* field = GetField( REFERENCE ); + wxASSERT( field != NULL ); + return *field; +} + + +bool LIB_PART::SaveDateAndTime( OUTPUTFORMATTER& aFormatter ) +{ + int year, mon, day, hour, min, sec; + + if( m_dateModified == 0 ) + return true; + + sec = m_dateModified & 63; + min = ( m_dateModified >> 6 ) & 63; + hour = ( m_dateModified >> 12 ) & 31; + day = ( m_dateModified >> 17 ) & 31; + mon = ( m_dateModified >> 22 ) & 15; + year = ( m_dateModified >> 26 ) + 1990; + + aFormatter.Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec ); + + return true; +} + + +bool LIB_PART::LoadDateAndTime( char* aLine ) +{ + int year, mon, day, hour, min, sec; + + year = mon = day = hour = min = sec = 0; + strtok( aLine, " \r\t\n" ); + strtok( NULL, " \r\t\n" ); + + if( sscanf( aLine, "%d/%d/%d %d:%d:%d", &year, &mon, &day, &hour, &min, &sec ) != 6 ) + return false; + + m_dateModified = ( sec & 63 ) + ( ( min & 63 ) << 6 ) + + ( ( hour & 31 ) << 12 ) + ( ( day & 31 ) << 17 ) + + ( ( mon & 15 ) << 22 ) + ( ( year - 1990 ) << 26 ); + + return true; +} + + +void LIB_PART::SetOffset( const wxPoint& aOffset ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + item.SetOffset( aOffset ); + } +} + + +void LIB_PART::RemoveDuplicateDrawItems() +{ + drawings.unique(); +} + + +bool LIB_PART::HasConversion() const +{ + for( unsigned ii = 0; ii < drawings.size(); ii++ ) + { + const LIB_ITEM& item = drawings[ii]; + if( item.m_Convert > 1 ) + return true; + } + + return false; +} + + +void LIB_PART::ClearStatus() +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + item.m_Flags = 0; + } +} + + +int LIB_PART::SelectItems( EDA_RECT& aRect, int aUnit, int aConvert, bool aEditPinByPin ) +{ + int itemCount = 0; + + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + item.ClearFlags( SELECTED ); + + if( ( item.m_Unit && item.m_Unit != aUnit ) + || ( item.m_Convert && item.m_Convert != aConvert ) ) + { + if( item.Type() != LIB_PIN_T ) + continue; + + // Specific rules for pins. + if( aEditPinByPin || m_unitsLocked + || ( item.m_Convert && item.m_Convert != aConvert ) ) + continue; + } + + if( item.Inside( aRect ) ) + { + item.SetFlags( SELECTED ); + itemCount++; + } + } + + return itemCount; +} + + +void LIB_PART::MoveSelectedItems( const wxPoint& aOffset ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( !item.IsSelected() ) + continue; + + item.SetOffset( aOffset ); + item.m_Flags = 0; + } + + drawings.sort(); +} + + +void LIB_PART::ClearSelectedItems() +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + item.m_Flags = 0; + } +} + + +void LIB_PART::DeleteSelectedItems() +{ + LIB_ITEMS::iterator item = drawings.begin(); + + // We *do not* remove the 2 mandatory fields: reference and value + // so skip them (do not remove) if they are flagged selected. + // Skip also not visible items. + // But I think fields must not be deleted by a block delete command or other global command + // because they are not really graphic items + while( item != drawings.end() ) + { + if( item->Type() == LIB_FIELD_T ) + { +#if 0 // Set to 1 to allows fields deletion on block delete or other global command + LIB_FIELD& field = ( LIB_FIELD& ) *item; + + if( (field.GetId() == REFERENCE) || (field.m_FieldId == VALUE) || + (field.m_Attributs & TEXT_NO_VISIBLE) ) +#endif + item->ClearFlags( SELECTED ); + } + + if( !item->IsSelected() ) + item++; + else + item = drawings.erase( item ); + } +} + + +void LIB_PART::CopySelectedItems( const wxPoint& aOffset ) +{ + /* *do not* use iterators here, because new items + * are added to drawings that is a boost::ptr_vector. + * When push_back elements in buffer, + * a memory reallocation can happen and will break pointers + */ + unsigned icnt = drawings.size(); + + for( unsigned ii = 0; ii < icnt; ii++ ) + { + LIB_ITEM& item = drawings[ii]; + + // We *do not* copy fields because they are unique for the whole component + // so skip them (do not duplicate) if they are flagged selected. + if( item.Type() == LIB_FIELD_T ) + item.ClearFlags( SELECTED ); + + if( !item.IsSelected() ) + continue; + + item.ClearFlags( SELECTED ); + LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); + newItem->SetFlags( SELECTED ); + drawings.push_back( newItem ); + } + + MoveSelectedItems( aOffset ); + drawings.sort(); +} + + + +void LIB_PART::MirrorSelectedItemsH( const wxPoint& aCenter ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( !item.IsSelected() ) + continue; + + item.MirrorHorizontal( aCenter ); + item.m_Flags = 0; + } + + drawings.sort(); +} + +void LIB_PART::MirrorSelectedItemsV( const wxPoint& aCenter ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( !item.IsSelected() ) + continue; + + item.MirrorVertical( aCenter ); + item.m_Flags = 0; + } + + drawings.sort(); +} + +void LIB_PART::RotateSelectedItems( const wxPoint& aCenter ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( !item.IsSelected() ) + continue; + + item.Rotate( aCenter ); + item.m_Flags = 0; + } + + drawings.sort(); +} + + + +LIB_ITEM* LIB_PART::LocateDrawItem( int aUnit, int aConvert, + KICAD_T aType, const wxPoint& aPoint ) +{ + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + if( ( aUnit && item.m_Unit && ( aUnit != item.m_Unit) ) + || ( aConvert && item.m_Convert && ( aConvert != item.m_Convert ) ) + || ( ( item.Type() != aType ) && ( aType != TYPE_NOT_INIT ) ) ) + continue; + + if( item.HitTest( aPoint ) ) + return &item; + } + + return NULL; +} + + +LIB_ITEM* LIB_PART::LocateDrawItem( int aUnit, int aConvert, KICAD_T aType, + const wxPoint& aPoint, const TRANSFORM& aTransform ) +{ + /* we use LocateDrawItem( int aUnit, int convert, KICAD_T type, const + * wxPoint& pt ) to search items. + * because this function uses DefaultTransform as orient/mirror matrix + * we temporary copy aTransform in DefaultTransform + */ + LIB_ITEM* item; + TRANSFORM transform = DefaultTransform; + DefaultTransform = aTransform; + + item = LocateDrawItem( aUnit, aConvert, aType, aPoint ); + + // Restore matrix + DefaultTransform = transform; + + return item; +} + + +void LIB_PART::SetUnitCount( int aCount ) +{ + if( m_unitCount == aCount ) + return; + + if( aCount < m_unitCount ) + { + LIB_ITEMS::iterator i; + i = drawings.begin(); + + while( i != drawings.end() ) + { + if( i->m_Unit > aCount ) + i = drawings.erase( i ); + else + i++; + } + } + else + { + int prevCount = m_unitCount; + + // We cannot use an iterator here, because when adding items in vector + // the buffer can be reallocated, that change the previous value of + // .begin() and .end() iterators and invalidate others iterators + unsigned imax = drawings.size(); + + for( unsigned ii = 0; ii < imax; ii++ ) + { + if( drawings[ii].m_Unit != 1 ) + continue; + + for( int j = prevCount + 1; j <= aCount; j++ ) + { + LIB_ITEM* newItem = (LIB_ITEM*) drawings[ii].Clone(); + newItem->m_Unit = j; + drawings.push_back( newItem ); + } + } + + drawings.sort(); + } + + m_unitCount = aCount; +} + + +void LIB_PART::SetConversion( bool aSetConvert ) +{ + if( aSetConvert == HasConversion() ) + return; + + // Duplicate items to create the converted shape + if( aSetConvert ) + { + std::vector< LIB_ITEM* > tmp; // Temporarily store the duplicated pins here. + + BOOST_FOREACH( LIB_ITEM& item, drawings ) + { + // Only pins are duplicated. + if( item.Type() != LIB_PIN_T ) + continue; + + if( item.m_Convert == 1 ) + { + LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); + newItem->m_Convert = 2; + tmp.push_back( newItem ); + } + } + + // Transfer the new pins to the LIB_PART. + for( unsigned i = 0; i < tmp.size(); i++ ) + drawings.push_back( tmp[i] ); + } + else + { + // Delete converted shape items because the converted shape does + // not exist + LIB_ITEMS::iterator i = drawings.begin(); + + while( i != drawings.end() ) + { + if( i->m_Convert > 1 ) + i = drawings.erase( i ); + else + i++; + } + } +} + + +wxArrayString LIB_PART::GetAliasNames( bool aIncludeRoot ) const +{ + wxArrayString names; + + LIB_ALIASES::const_iterator it; + + for( it=m_aliases.begin(); itIsRoot() ) + continue; + + names.Add( (*it)->GetName() ); + } + + return names; +} + + +bool LIB_PART::HasAlias( const wxString& aName ) const +{ + wxCHECK2_MSG( !aName.IsEmpty(), return false, + wxT( "Cannot get alias with an empty name, bad programmer." ) ); + + for( size_t i = 0; i < m_aliases.size(); i++ ) + { + if( Cmp_KEEPCASE( aName, m_aliases[i]->GetName() ) == 0 ) + return true; + } + + return false; +} + + +void LIB_PART::SetAliases( const wxArrayString& aAliasList ) +{ + wxCHECK_RET( !m_library, + wxT( "Part aliases cannot be changed when they are owned by a library." ) ); + + if( aAliasList == GetAliasNames() ) + return; + + // Add names not existing in the current component alias list. + for( size_t i = 0; i < aAliasList.GetCount(); i++ ) + { + if( HasAlias( aAliasList[ i ] ) ) + continue; + + m_aliases.push_back( new LIB_ALIAS( aAliasList[ i ], this ) ); + } + + // Remove names in the current component that are not in the new alias list. + LIB_ALIASES::iterator it = m_aliases.begin(); + + while( it != m_aliases.end() ) + { + int index = aAliasList.Index( (*it)->GetName(), false ); + + if( index != wxNOT_FOUND || (*it)->IsRoot() ) + ++it; + else + it = m_aliases.erase( it ); + } +} + + +#if 0 // this version looked suspect to me, it did not rename a deleted root + +void LIB_PART::RemoveAlias( const wxString& aName ) +{ + wxCHECK_RET( m_library == NULL, + wxT( "Part aliases cannot be changed when they are owned by a library." ) ); + wxCHECK_RET( !aName.IsEmpty(), wxT( "Cannot get alias with an empty name." ) ); + + LIB_ALIASES::iterator it; + + for( it = m_aliases.begin(); it < m_aliases.end(); it++ ) + { + if( Cmp_KEEPCASE( aName, (*it)->GetName() ) == 0 ) + { + m_aliases.erase( it ); + break; + } + } +} + +#else +void LIB_PART::RemoveAlias( const wxString& aName ) +{ + LIB_ALIAS* a = GetAlias( aName ); + + if( a ) + RemoveAlias( a ); +} +#endif + + +LIB_ALIAS* LIB_PART::RemoveAlias( LIB_ALIAS* aAlias ) +{ + wxCHECK_MSG( aAlias, NULL, wxT( "Cannot remove alias by NULL pointer." ) ); + + LIB_ALIAS* nextAlias = NULL; + + LIB_ALIASES::iterator it = find( m_aliases.begin(), m_aliases.end(), aAlias ); + + if( it != m_aliases.end() ) + { + bool rename = aAlias->IsRoot(); + + wxLogTrace( traceSchLibMem, + wxT( "%s: part:'%s', alias:'%s', alias count %llu, reference count %ld." ), + GetChars( wxString::FromAscii( __WXFUNCTION__ ) ), + GetChars( m_name ), + GetChars( aAlias->GetName() ), + (long long unsigned) m_aliases.size(), + m_me.use_count() ); + + it = m_aliases.erase( it ); + + if( !m_aliases.empty() ) + { + if( it == m_aliases.end() ) + it = m_aliases.begin(); + + nextAlias = *it; + + if( rename ) + SetName( nextAlias->GetName() ); + } + } + + return nextAlias; +} + + +void LIB_PART::RemoveAllAliases() +{ + // Remove all of the aliases except the root alias. + while( m_aliases.size() > 1 ) + m_aliases.pop_back(); +} + + +LIB_ALIAS* LIB_PART::GetAlias( const wxString& aName ) +{ + wxCHECK2_MSG( !aName.IsEmpty(), return NULL, + wxT( "Cannot get alias with an empty name. Bad programmer!" ) ); + + for( size_t i = 0; i < m_aliases.size(); i++ ) + { + if( Cmp_KEEPCASE( aName, m_aliases[i]->GetName() ) == 0 ) + return m_aliases[i]; + } + + return NULL; +} + + +LIB_ALIAS* LIB_PART::GetAlias( size_t aIndex ) +{ + wxCHECK2_MSG( aIndex < m_aliases.size(), return NULL, + wxT( "Illegal alias list index, bad programmer." ) ); + + return m_aliases[aIndex]; +} + + +void LIB_PART::AddAlias( const wxString& aName ) +{ + wxCHECK_RET( !HasAlias( aName ), + wxT( "Part <" ) + GetName() + wxT( "> already has an alias <" ) + + aName + wxT( ">. Bad programmer." ) ); + + m_aliases.push_back( new LIB_ALIAS( aName, this ) ); +} + + +void LIB_PART::SetSubpartIdNotation( int aSep, int aFirstId ) +{ + m_subpartFirstId = 'A'; + m_subpartIdSeparator = 0; + + if( aSep == '.' || aSep == '-' || aSep == '_' ) + m_subpartIdSeparator = aSep; + + if( aFirstId == '1' && aSep != 0 ) + m_subpartFirstId = aFirstId; +} diff --git a/eeschema/class_libentry.h b/eeschema/class_libentry.h new file mode 100644 index 00000000..b81859eb --- /dev/null +++ b/eeschema/class_libentry.h @@ -0,0 +1,773 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_libentry.h + */ + +#ifndef CLASS_LIBENTRY_H +#define CLASS_LIBENTRY_H + +#include +#include +#include +#include +#include +#include + +class LINE_READER; +class OUTPUTFORMATTER; +class PART_LIB; +class LIB_ALIAS; +class LIB_PART; +class LIB_FIELD; + + +/// Compiler controlled string compare function, either case independent or not: +inline int Cmp_KEEPCASE( const wxString& aString1, const wxString& aString2 ) +{ +#ifdef KICAD_KEEPCASE + // case specificity, the normal behavior: + return aString1.Cmp( aString2 ); +#else + // case independence (only for guys who want that: not recommended) + return aString1.CmpNoCase( aString2 ); +#endif +} + + +typedef std::vector LIB_ALIASES; +typedef boost::shared_ptr PART_SPTR; ///< shared pointer to LIB_PART +typedef boost::weak_ptr PART_REF; ///< weak pointer to LIB_PART + + +/* values for member .m_options */ +enum LIBRENTRYOPTIONS +{ + ENTRY_NORMAL, // Libentry is a standard part (real or alias) + ENTRY_POWER // Libentry is a power symbol +}; + + +/// WXTRACE value to enable schematic library memory deletion debug output. +extern const wxChar traceSchLibMem[]; + + +/** + * Part library alias object definition. + * + * Part aliases are not really parts. An alias uses the part definition + * (graphic, pins...) but has its own name, keywords and documentation. Therefore, when + * the part is modified, alias of this part are modified. This is a simple + * method to create parts that have the same physical layout with different names + * such as 74LS00, 74HC00 ... and many op amps. + */ +class LIB_ALIAS : public EDA_ITEM +{ + /** + * Actual LIB_PART referenced by [multiple] aliases. + * + * @note - Do not delete the shared part. The shared part is shared by + * all of the aliases associated with it. A shared LIB_PART will + * be deleted when all LIB_ALIASes pointing to it are deleted. + */ + LIB_PART* shared; + + friend class LIB_PART; + +protected: + wxString name; + wxString description; ///< documentation for info + wxString keyWords; ///< keyword list (used for search for parts by keyword) + wxString docFileName; ///< Associate doc file name + +public: + LIB_ALIAS( const wxString& aName, LIB_PART* aRootComponent ); + LIB_ALIAS( const LIB_ALIAS& aAlias, LIB_PART* aRootComponent = NULL ); + + virtual ~LIB_ALIAS(); + + virtual wxString GetClass() const + { + return wxT( "LIB_ALIAS" ); + } + + /** + * Function GetPart + * gets the shared LIB_PART. + * + * @return LIB_PART* - the LIB_PART shared by + * this LIB_ALIAS with possibly other LIB_ALIASes. + */ + LIB_PART* GetPart() const + { + return shared; + } + + const wxString GetLibraryName(); + + bool IsRoot() const; + + PART_LIB* GetLib(); + + const wxString& GetName() const { return name; } + + void SetName( const wxString& aName ) { name = aName; } + + void SetDescription( const wxString& aDescription ) + { + description = aDescription; + } + + wxString GetDescription() const { return description; } + + void SetKeyWords( const wxString& aKeyWords ) + { + keyWords = aKeyWords; + } + + wxString GetKeyWords() const { return keyWords; } + + void SetDocFileName( const wxString& aDocFileName ) + { + docFileName = aDocFileName; + } + + wxString GetDocFileName() const { return docFileName; } + + /** + * Function SaveDocs + * write the entry document information to \a aFormatter in "*.dcm" format. + * + * @param aFormatter The #OUTPUTFORMATTER to write the alias documents to. + * @return True if success writing else false. + */ + bool SaveDoc( OUTPUTFORMATTER& aFormatter ); + + /** + * KEEPCASE sensitive comparison of the part entry name. + */ + bool operator==( const wxChar* aName ) const; + bool operator!=( const wxChar* aName ) const + { + return !( *this == aName ); + } + + bool operator==( const LIB_ALIAS* aAlias ) const { return this == aAlias; } + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif +}; + +extern bool operator<( const LIB_ALIAS& aItem1, const LIB_ALIAS& aItem2 ); + +extern int LibraryEntryCompare( const LIB_ALIAS* aItem1, const LIB_ALIAS* aItem2 ); + + +/** + * Class LIB_PART + * defines a library part object. + * + * A library part object is typically saved and loaded in a part library file (.lib). + * Library parts are different from schematic components. + */ +class LIB_PART : public EDA_ITEM +{ + friend class PART_LIB; + friend class LIB_ALIAS; + + PART_SPTR m_me; ///< http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared + wxString m_name; + int m_pinNameOffset; ///< The offset in mils to draw the pin name. Set to 0 + ///< to draw the pin name above the pin. + bool m_unitsLocked; ///< True if part has multiple units and changing + ///< one unit does not automatically change another unit. + bool m_showPinNames; ///< Determines if part pin names are visible. + bool m_showPinNumbers; ///< Determines if part pin numbers are visible. + long m_dateModified; ///< Date the part was last modified. + LIBRENTRYOPTIONS m_options; ///< Special part features such as POWER or NORMAL.) + int m_unitCount; ///< Number of units (parts) per package. + LIB_ITEMS drawings; ///< How to draw this part. + wxArrayString m_FootprintList; /**< List of suitable footprint names for the + part (wild card names accepted). */ + LIB_ALIASES m_aliases; ///< List of alias object pointers associated with the + ///< part. + PART_LIB* m_library; ///< Library the part belongs to if any. + + static int m_subpartIdSeparator; ///< the separator char between + ///< the subpart id and the reference + ///< like U1A ( m_subpartIdSeparator = 0 ) or U1.A or U1-A + static int m_subpartFirstId; ///< the ascii char value to calculate the subpart symbol id + ///< from the part number: only 'A', 'a' or '1' can be used, + ///< other values have no sense. +private: + void deleteAllFields(); + + // LIB_PART() { } // not legal + +public: + + LIB_PART( const wxString& aName, PART_LIB* aLibrary = NULL ); + LIB_PART( LIB_PART& aPart, PART_LIB* aLibrary = NULL ); + + virtual ~LIB_PART(); + + PART_SPTR SharedPtr() + { + // clone a shared pointer + return m_me; + } + + virtual wxString GetClass() const + { + return wxT( "LIB_PART" ); + } + + virtual void SetName( const wxString& aName ); + + const wxString& GetName() { return m_name; } + + const wxString GetLibraryName(); + + PART_LIB* GetLib() { return m_library; } + + wxArrayString GetAliasNames( bool aIncludeRoot = true ) const; + + size_t GetAliasCount() const { return m_aliases.size(); } + + LIB_ALIAS* GetAlias( size_t aIndex ); + + LIB_ALIAS* GetAlias( const wxString& aName ); + + /** + * Function AddAlias + * + * Add an alias \a aName to the part. + * + * Duplicate alias names are not added to the alias list. Debug builds will raise an + * assertion. Release builds will fail silently. + * + * @param aName - Name of alias to add. + */ + void AddAlias( const wxString& aName ); + + /** + * Test if alias \a aName is in part alias list. + * + * Alias name comparisons are case insensitive. + * + * @param aName - Name of alias. + * @return True if alias name in alias list. + */ + bool HasAlias( const wxString& aName ) const; + + void SetAliases( const wxArrayString& aAliasList ); + + void RemoveAlias( const wxString& aName ); + LIB_ALIAS* RemoveAlias( LIB_ALIAS* aAlias ); + + void RemoveAllAliases(); + + wxArrayString& GetFootPrints() { return m_FootprintList; } + + /** + * Function GetBoundingBox + * @return the part bounding box ( in user coordinates ) + * @param aUnit = unit selection = 0, or 1..n + * @param aConvert = 0, 1 or 2 + * If aUnit == 0, unit is not used + * if aConvert == 0 Convert is non used + * Invisible fields are not taken in account + **/ + const EDA_RECT GetBoundingBox( int aUnit, int aConvert ) const; + + /** + * Function GetBodyBoundingBox + * @return the part bounding box ( in user coordinates ) without fields + * @param aUnit = unit selection = 0, or 1..n + * @param aConvert = 0, 1 or 2 + * If aUnit == 0, unit is not used + * if aConvert == 0 Convert is non used + * Fields are not taken in account + **/ + const EDA_RECT GetBodyBoundingBox( int aUnit, int aConvert ) const; + + /** + * Function SaveDateAndTime + * write the date and time of part to \a aFile in the format: + * "Ti yy/mm/jj hh:mm:ss" + * + * @param aFormatter A reference to an #OUTPUTFORMATTER object containing the + * output format to write to. + * @return True if the date and time were successfully written to \a aFormatter. + */ + bool SaveDateAndTime( OUTPUTFORMATTER& aFormatter ); + + bool LoadDateAndTime( char* aLine ); + + /** + * Function Save + * writes the data structures out to \a aFormatter in the part library "*.lib" + * format. + * + * @param aFormatter A reference to an OUTPUTFORMATTER to write to. + * @return True if success writing else false. + */ + bool Save( OUTPUTFORMATTER& aFormatter ); + + /** + * Load part definition from \a aReader. + * + * @param aReader A LINE_READER object to load file from. + * @param aErrorMsg - Description of error on load failure. + * @return True if the load was successful, false if there was an error. + */ + bool Load( LINE_READER& aReader, wxString& aErrorMsg ); + bool LoadField( LINE_READER& aReader, wxString& aErrorMsg ); + bool LoadDrawEntries( LINE_READER& aReader, wxString& aErrorMsg ); + bool LoadAliases( char* aLine, wxString& aErrorMsg ); + bool LoadFootprints( LINE_READER& aReader, wxString& aErrorMsg ); + + bool IsPower() const { return m_options == ENTRY_POWER; } + bool IsNormal() const { return m_options == ENTRY_NORMAL; } + + void SetPower() { m_options = ENTRY_POWER; } + void SetNormal() { m_options = ENTRY_NORMAL; } + + void LockUnits( bool aLockUnits ) { m_unitsLocked = aLockUnits; } + bool UnitsLocked() const { return m_unitsLocked; } + + /** + * Function SetFields + * overwrites all the existing in this part with fields supplied + * in \a aFieldsList. The only known caller of this function is the + * library part field editor, and it establishes needed behavior. + * +` * @param aFieldsList is a set of fields to import, removing all previous fields. + */ + void SetFields( const std::vector & aFieldsList ); + + /** + * Function GetFields + * returns a list of fields withing this part. The only known caller of + * this function is the library part field editor, and it establishes + * needed behavior. + * + * @param aList - List to add fields to + */ + void GetFields( LIB_FIELDS& aList ); + + /** + * Function FindField + * finds a field within this part matching \a aFieldName and returns + * it or NULL if not found. + */ + LIB_FIELD* FindField( const wxString& aFieldName ); + + /** + * Return pointer to the requested field. + * + * @param aId - Id of field to return. + * @return The field if found, otherwise NULL. + */ + LIB_FIELD* GetField( int aId ); + + /** Return reference to the value field. */ + LIB_FIELD& GetValueField(); + + /** Return reference to the reference designator field. */ + LIB_FIELD& GetReferenceField(); + + /** + * Draw part. + * + * @param aPanel - Window to draw on. Can be NULL if not available. + * @param aDc - Device context to draw on. + * @param aOffset - Position of part. + * @param aMulti - unit if multiple units per part. + * @param aConvert - Component conversion (DeMorgan) if available. + * @param aDrawMode - Device context drawing mode, see wxDC. + * @param aColor - Color to draw part. + * @param aTransform - Coordinate adjustment settings. + * @param aShowPinText - Show pin text if true. + * @param aDrawFields - Draw field text if true otherwise just draw + * body items (useful to draw a body in schematic, + * because fields of schematic components replace + * the lib part fields). + * @param aOnlySelected - Draws only the body items that are selected. + * Used for block move redraws. + * @param aPinsDangling - if not NULL, this should be a pointer to + * vector exactly the same length as the number of pins, + * indicating whether each pin is dangling. If NULL, all pins + * will be drawn as if they were dangling. + */ + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDc, const wxPoint& aOffset, + int aMulti, int aConvert, GR_DRAWMODE aDrawMode, + EDA_COLOR_T aColor = UNSPECIFIED_COLOR, + const TRANSFORM& aTransform = DefaultTransform, + bool aShowPinText = true, bool aDrawFields = true, + bool aOnlySelected = false, + const std::vector* aPinsDangling = NULL ); + + /** + * Plot lib part to plotter. + * Lib Fields not are plotted here, because this plot function + * is used to plot schematic items, which have they own fields + * + * @param aPlotter - Plotter object to plot to. + * @param aUnit - Component part to plot. + * @param aConvert - Component alternate body style to plot. + * @param aOffset - Distance to shift the plot coordinates. + * @param aTransform - Component plot transform matrix. + */ + void Plot( PLOTTER* aPlotter, int aUnit, int aConvert, const wxPoint& aOffset, + const TRANSFORM& aTransform ); + + /** + * Plot Lib Fields only of the part to plotter. + * is used to plot the full lib part, outside the schematic + * + * @param aPlotter - Plotter object to plot to. + * @param aUnit - Component part to plot. + * @param aConvert - Component alternate body style to plot. + * @param aOffset - Distance to shift the plot coordinates. + * @param aTransform - Component plot transform matrix. + */ + void PlotLibFields( PLOTTER* aPlotter, int aUnit, int aConvert, + const wxPoint& aOffset, const TRANSFORM& aTransform ); + + /** + * Add a new draw \a aItem to the draw object list. + * + * @param aItem - New draw object to add to part. + */ + void AddDrawItem( LIB_ITEM* aItem ); + + /** + * Remove draw \a aItem from list. + * + * @param aItem - Draw item to remove from list. + * @param aPanel - Panel to remove part from. + * @param aDc - Device context to remove part from. + */ + void RemoveDrawItem( LIB_ITEM* aItem, EDA_DRAW_PANEL* aPanel = NULL, wxDC* aDc = NULL ); + + /** + * Return the next draw object pointer. + * + * @param aItem - Pointer to the current draw item. Setting item NULL + * with return the first item of type in the list. + * @param aType - type of searched item (filter). + * if TYPE_NOT_INIT search for all items types + * @return - The next drawing object in the list if found, otherwise NULL. + */ + LIB_ITEM* GetNextDrawItem( LIB_ITEM* aItem = NULL, KICAD_T aType = TYPE_NOT_INIT ); + + /** + * Return the next pin object from the draw list. + * + * This is just a pin object specific version of GetNextDrawItem(). + * + * @param aItem - Pointer to the previous pin item, or NULL to get the + * first pin in the draw object list. + * @return - The next pin object in the list if found, otherwise NULL. + */ + LIB_PIN* GetNextPin( LIB_PIN* aItem = NULL ) + { + return (LIB_PIN*) GetNextDrawItem( (LIB_ITEM*) aItem, LIB_PIN_T ); + } + + + /** + * Return a list of pin object pointers from the draw item list. + * + * Note pin objects are owned by the draw list of the part. + * Deleting any of the objects will leave list in a unstable state + * and will likely segfault when the list is destroyed. + * + * @param aList - Pin list to place pin object pointers into. + * @param aUnit - Unit number of pin to add to list. Set to 0 to + * get pins from any part unit. + * @param aConvert - Convert number of pin to add to list. Set to 0 to + * get pins from any convert of part. + */ + void GetPins( LIB_PINS& aList, int aUnit = 0, int aConvert = 0 ); + + /** + * Return pin object with the requested pin \a aNumber. + * + * @param aNumber - Number of the pin to find. + * @param aUnit - Unit of the part to find. Set to 0 if a specific + * unit number is not required. + * @param aConvert - Alternate body style filter (DeMorgan). Set to 0 if + * no alternate body style is required. + * @return The pin object if found. Otherwise NULL. + */ + LIB_PIN* GetPin( const wxString& aNumber, int aUnit = 0, int aConvert = 0 ); + + /** + * Function PinsConflictWith + * returns true if this part's pins do not match another part's pins. This + * is used to detect whether the project cache is out of sync with the + * system libs. + * + * @param aOtherPart - The other library part to test + * @param aTestNums - Whether two pins at the same point must have the same number. + * @param aTestNames - Whether two pins at the same point must have the same name. + * @param aTestType - Whether two pins at the same point must have the same electrical type. + * @param aTestOrientation - Whether two pins at the same point must have the same orientation. + * @param aTestLength - Whether two pins at the same point must have the same length. + */ + bool PinsConflictWith( LIB_PART& aOtherPart, bool aTestNums, bool aTestNames, + bool aTestType, bool aTestOrientation, bool aTestLength ); + + /** + * Move the part \a aOffset. + * + * @param aOffset - Offset displacement. + */ + void SetOffset( const wxPoint& aOffset ); + + /** + * Remove duplicate draw items from list. + */ + void RemoveDuplicateDrawItems(); + + /** + * Test if part has more than one body conversion type (DeMorgan). + * + * @return True if part has more than one conversion. + */ + bool HasConversion() const; + + /** + * Clears the status flag all draw objects in this part. + */ + void ClearStatus(); + + /** + * Checks all draw objects of part to see if they are with block. + * + * Use this method to mark draw objects as selected during block + * functions. + * + * @param aRect - The bounding rectangle to test in draw items are inside. + * @param aUnit - The current unit number to test against. + * @param aConvert - Are the draw items being selected a conversion. + * @param aEditPinByPin - Used to ignore pin selections when in edit pin + * by pin mode is enabled. + * @return The number of draw objects found inside the block select + * rectangle. + */ + int SelectItems( EDA_RECT& aRect, int aUnit, int aConvert, bool aEditPinByPin ); + + /** + * Clears all the draw items marked by a block select. + */ + void ClearSelectedItems(); + + /** + * Deletes the select draw items marked by a block select. + * + * The name and reference field will not be deleted. They are the + * minimum drawing items required for any part. Their properties + * can be changed but the cannot be removed. + */ + void DeleteSelectedItems(); + + /** + * Move the selected draw items marked by a block select. + */ + void MoveSelectedItems( const wxPoint& aOffset ); + + /** + * Make a copy of the selected draw items marked by a block select. + * + * Fields are not copied. Only part body items are copied. + * Copying fields would result in duplicate fields which does not + * make sense in this context. + */ + void CopySelectedItems( const wxPoint& aOffset ); + + /** + * Horizontally (X axis) mirror selected draw items about a point. + * + * @param aCenter - Center point to mirror around. + */ + void MirrorSelectedItemsH( const wxPoint& aCenter ); + + /** + * Vertically (Y axis) mirror selected draw items about a point. + * + * @param aCenter - Center point to mirror around. + */ + void MirrorSelectedItemsV( const wxPoint& aCenter ); + + /** + * Rotate CCW selected draw items about a point. + * + * @param aCenter - Center point to mirror around. + */ + void RotateSelectedItems( const wxPoint& aCenter ); + + /** + * Locate a draw object. + * + * @param aUnit - Unit number of draw item. + * @param aConvert - Body style of draw item. + * @param aType - Draw object type, set to 0 to search for any type. + * @param aPoint - Coordinate for hit testing. + * @return The draw object if found. Otherwise NULL. + */ + LIB_ITEM* LocateDrawItem( int aUnit, int aConvert, KICAD_T aType, const wxPoint& aPoint ); + + /** + * Locate a draw object (overlaid) + * + * @param aUnit - Unit number of draw item. + * @param aConvert - Body style of draw item. + * @param aType - Draw object type, set to 0 to search for any type. + * @param aPoint - Coordinate for hit testing. + * @param aTransform = the transform matrix + * @return The draw object if found. Otherwise NULL. + */ + LIB_ITEM* LocateDrawItem( int aUnit, int aConvert, KICAD_T aType, + const wxPoint& aPoint, const TRANSFORM& aTransform ); + + /** + * Return a reference to the draw item list. + * + * @return LIB_ITEMS& - Reference to the draw item object list. + */ + LIB_ITEMS& GetDrawItemList() { return drawings; } + + /** + * Set the units per part count. + * + * If the count is greater than the current count, then the all of the + * current draw items are duplicated for each additional part. If the + * count is less than the current count, all draw objects for units + * greater that count are removed from the part. + * + * @param count - Number of units per package. + */ + void SetUnitCount( int count ); + + int GetUnitCount() const { return m_unitCount; } + + /** + * Function IsMulti + * @return true if the part has multiple units per part. + * When happens, the reference has a sub reference ti identify part + */ + bool IsMulti() const { return m_unitCount > 1; } + + /** + * Function SubReference + * @return the sub reference for part having multiple units per part. + * The sub reference identify the part (or unit) + * @param aUnit = the part identifier ( 1 to max count) + * @param aAddSeparator = true (default) to prpebd the sub ref + * by the separator symbol (if any) + * Note: this is a static function. + */ + static wxString SubReference( int aUnit, bool aAddSeparator = true ); + + // Accessors to sub ref parameters + static int GetSubpartIdSeparator() { return m_subpartIdSeparator; } + + /** return a reference to m_subpartIdSeparator, + * only for read/save setting functions + */ + static int* SubpartIdSeparatorPtr() { return &m_subpartIdSeparator; } + + static int GetSubpartFirstId() { return m_subpartFirstId; } + + /** return a reference to m_subpartFirstId, only for read/save setting functions + */ + static int* SubpartFirstIdPtr() { return &m_subpartFirstId; } + + /** Set the separator char between the subpart id and the reference + * 0 (no separator) or '.' , '-' and '_' + * and the ascii char value to calculate the subpart symbol id from the part number: + * 'A' or '1' only are allowed. (to print U1.A or U1.1) + * if this is a digit, a number is used as id symbol + * Note also if the subpart symbol is a digit, the separator cannot be null. + * @param aSep = the separator symbol (0 (no separator) or '.' , '-' and '_') + * @param aFirstId = the Id of the first part ('A' or '1') + */ + static void SetSubpartIdNotation( int aSep, int aFirstId ); + + /** + * Set or clear the alternate body style (DeMorgan) for the part. + * + * If the part already has an alternate body style set and a + * asConvert if false, all of the existing draw items for the alternate + * body style are remove. If the alternate body style is not set and + * asConvert is true, than the base draw items are duplicated and + * added to the part. + * + * @param aSetConvert - Set or clear the part alternate body style. + */ + void SetConversion( bool aSetConvert ); + + /** + * Set the offset in mils of the pin name text from the pin symbol. + * + * Set the offset to 0 to draw the pin name above the pin symbol. + * + * @param aOffset - The offset in mils. + */ + void SetPinNameOffset( int aOffset ) { m_pinNameOffset = aOffset; } + + int GetPinNameOffset() { return m_pinNameOffset; } + + /** + * Set or clear the pin name visibility flag. + * + * @param aShow - True to make the part pin names visible. + */ + void SetShowPinNames( bool aShow ) { m_showPinNames = aShow; } + + bool ShowPinNames() { return m_showPinNames; } + + /** + * Set or clear the pin number visibility flag. + * + * @param aShow - True to make the part pin numbers visible. + */ + void SetShowPinNumbers( bool aShow ) { m_showPinNumbers = aShow; } + + bool ShowPinNumbers() { return m_showPinNumbers; } + + bool operator==( const LIB_PART* aPart ) const { return this == aPart; } + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif +}; + +#endif // CLASS_LIBENTRY_H diff --git a/eeschema/class_library.cpp b/eeschema/class_library.cpp new file mode 100644 index 00000000..93a5331e --- /dev/null +++ b/eeschema/class_library.cpp @@ -0,0 +1,1208 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_library.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define duplicate_name_msg \ + _( "Library '%s' has duplicate entry name '%s'.\n" \ + "This may cause some unexpected behavior when loading components into a schematic." ) + + +PART_LIB::PART_LIB( int aType, const wxString& aFileName ) : + // start @ != 0 so each additional library added + // is immediately detectable, zero would not be. + m_mod_hash( PART_LIBS::s_modify_generation ) +{ + type = aType; + isModified = false; + timeStamp = 0; + isCache = false; + timeStamp = wxDateTime::Now(); + versionMajor = 0; // Will be updated after reading the lib file + versionMinor = 0; // Will be updated after reading the lib file + + fileName = aFileName; + + if( !fileName.IsOk() ) + fileName = wxT( "unnamed.lib" ); +} + + +PART_LIB::~PART_LIB() +{ + // When the library is destroyed, all of the alias objects on the heap should be deleted. + for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it != m_amap.end(); ++it ) + { + wxLogTrace( traceSchLibMem, wxT( "Removing alias %s from library %s." ), + GetChars( it->second->GetName() ), GetChars( GetLogicalName() ) ); + LIB_PART* part = it->second->GetPart(); + LIB_ALIAS* alias = it->second; + delete alias; + + // When the last alias of a part is destroyed, the part is no longer required and it + // too is destroyed. + if( part && part->GetAliasCount() == 0 ) + delete part; + } + + m_amap.clear(); +} + + +void PART_LIB::GetEntryNames( wxArrayString& aNames, bool aSort, bool aMakeUpperCase ) +{ + for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ ) + { + if( aMakeUpperCase ) + { + wxString tmp = (*it).first; + tmp.MakeUpper(); + aNames.Add( tmp ); + } + else + { + aNames.Add( (*it).first ); + } + } + + if( aSort ) + aNames.Sort(); +} + + +void PART_LIB::GetEntryTypePowerNames( wxArrayString& aNames, bool aSort, bool aMakeUpperCase ) +{ + for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ ) + { + LIB_ALIAS* alias = it->second; + LIB_PART* root = alias->GetPart(); + + if( !root || !root->IsPower() ) + continue; + + if( aMakeUpperCase ) + { + wxString tmp = (*it).first; + tmp.MakeUpper(); + aNames.Add( tmp ); + } + else + { + aNames.Add( (*it).first ); + } + } + + if( aSort ) + aNames.Sort(); +} + + +/** + * Function sortFunction + * simple function used as comparator to sort a std::vector&. + * + * @param aItem1 is the first comparison parameter. + * @param aItem2 is the second. + * @return bool - which item should be put first in the sorted list. + */ +bool sortFunction( wxArrayString aItem1, wxArrayString aItem2 ) +{ + return( aItem1.Item( 0 ) < aItem2.Item( 0 ) ); +} + + +void PART_LIB::SearchEntryNames( std::vector& aNames, + const wxString& aNameSearch, + const wxString& aKeySearch, + bool aSort ) +{ + for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it != m_amap.end(); ++it ) + { + if( !!aKeySearch && KeyWordOk( aKeySearch, it->second->GetKeyWords() ) ) + { + wxArrayString item; + + item.Add( it->first ); + item.Add( GetLogicalName() ); + aNames.push_back( item ); + } + + if( !aNameSearch.IsEmpty() && + WildCompareString( aNameSearch, it->second->GetName(), false ) ) + { + wxArrayString item; + + item.Add( it->first ); + item.Add( GetLogicalName() ); + aNames.push_back( item ); + } + } + + if( aSort ) + std::sort( aNames.begin(), aNames.end(), sortFunction ); +} + + +void PART_LIB::SearchEntryNames( wxArrayString& aNames, const wxRegEx& aRe, bool aSort ) +{ + if( !aRe.IsValid() ) + return; + + LIB_ALIAS_MAP::iterator it; + + for( it = m_amap.begin(); it!=m_amap.end(); it++ ) + { + if( aRe.Matches( it->second->GetKeyWords() ) ) + aNames.Add( it->first ); + } + + if( aSort ) + aNames.Sort(); +} + + +bool PART_LIB::Conflicts( LIB_PART* aPart ) +{ + wxCHECK_MSG( aPart != NULL, false, + wxT( "Cannot test NULL component for conflicts in library " ) + GetName() ); + + for( size_t i=0; im_aliases.size(); i++ ) + { + LIB_ALIAS_MAP::iterator it = m_amap.find( aPart->m_aliases[i]->GetName() ); + + if( it != m_amap.end() ) + return true; + } + + return false; +} + + +LIB_ALIAS* PART_LIB::FindEntry( const wxString& aName ) +{ + LIB_ALIAS_MAP::iterator it = m_amap.find( aName ); + + if( it != m_amap.end() ) + return it->second; + + return NULL; +} + + +LIB_ALIAS* PART_LIB::GetFirstEntry() +{ + if( m_amap.size() ) + return m_amap.begin()->second; + else + return NULL; +} + + +LIB_PART* PART_LIB::FindPart( const wxString& aName ) +{ +#if 0 && defined(DEBUG) + if( !aName.Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) ) + { + int breakhere = 1; + (void) breakhere; + } +#endif + + if( LIB_ALIAS* alias = FindEntry( aName ) ) + { + return alias->GetPart(); + } + + return NULL; +} + + +bool PART_LIB::HasPowerParts() +{ + // return true if at least one power part is found in lib + for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ ) + { + LIB_ALIAS* alias = it->second; + LIB_PART* root = alias->GetPart(); + + if( root && root->IsPower() ) + return true; + } + + return false; +} + + +bool PART_LIB::AddAlias( LIB_ALIAS* aAlias ) +{ + wxASSERT( aAlias ); + +#if defined(DEBUG) && 0 + if( !aAlias->GetName().Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) ) + { + int breakhere = 1; + (void) breakhere; + } +#endif + + LIB_ALIAS_MAP::iterator it = m_amap.find( aAlias->GetName() ); + + if( it != m_amap.end() ) + { + wxString msg; + + msg.Printf( _( "Cannot add duplicate alias '%s' to library '%s'." ), + GetChars( aAlias->GetName() ), + GetChars( fileName.GetName() ) ); + return false; + } + + wxString name = aAlias->GetName(); + + m_amap[ name ] = aAlias; + isModified = true; + ++m_mod_hash; + + return true; +} + + +bool PART_LIB::AddPart( LIB_PART* aPart ) +{ + // Conflict detection: See if already existing aliases exist, + // and if yes, ask user for continue or abort + // Special case: if the library is the library cache of the project, + // old aliases are always removed to avoid conflict, + // and user is not prompted ) + if( Conflicts( aPart ) && !IsCache() ) + { + wxFAIL_MSG( wxT( "Cannot add component <" ) + aPart->GetName() + + wxT( "> to library <" ) + GetName() + wxT( "> due to name conflict." ) ); + return false; + } + + // add a clone, not the caller's copy + LIB_PART* my_part = new LIB_PART( *aPart, this ); + + for( size_t i = 0; i < my_part->m_aliases.size(); i++ ) + { + wxString aliasname = my_part->m_aliases[i]->GetName(); + + if( LIB_ALIAS* alias = FindAlias( aliasname ) ) + RemoveEntry( alias ); + + m_amap[ aliasname ] = my_part->m_aliases[i]; + } + + isModified = true; + ++m_mod_hash; + + return true; +} + + +LIB_ALIAS* PART_LIB::RemoveEntry( LIB_ALIAS* aEntry ) +{ + wxCHECK_MSG( aEntry != NULL, NULL, wxT( "NULL pointer cannot be removed from library." ) ); + + LIB_ALIAS_MAP::iterator it = m_amap.find( aEntry->GetName() ); + + if( it == m_amap.end() ) + return NULL; + + // If the entry pointer doesn't match the name it is mapped to in the library, we + // have done something terribly wrong. + wxCHECK_MSG( *it->second == aEntry, NULL, + wxT( "Pointer mismatch while attempting to remove entry <" ) + + aEntry->GetName() + wxT( "> from library <" ) + GetName() + wxT( ">." ) ); + + LIB_ALIAS* alias = aEntry; + LIB_PART* part = alias->GetPart(); + + alias = part->RemoveAlias( alias ); + + if( !alias ) + { + delete part; + + if( m_amap.size() > 1 ) + { + LIB_ALIAS_MAP::iterator next = it; + next++; + + if( next == m_amap.end() ) + next = m_amap.begin(); + + alias = next->second; + } + } + + m_amap.erase( it ); + isModified = true; + ++m_mod_hash; + return alias; +} + + +LIB_PART* PART_LIB::ReplacePart( LIB_PART* aOldPart, LIB_PART* aNewPart ) +{ + wxASSERT( aOldPart != NULL ); + wxASSERT( aNewPart != NULL ); + + /* Remove the old root component. The component will automatically be deleted + * when all it's aliases are deleted. Do not place any code that accesses + * aOldPart inside this loop that gets evaluated after the last alias is + * removed in RemoveEntry(). Failure to heed this warning will result in a + * segfault. + */ + size_t i = aOldPart->m_aliases.size(); + + while( i > 0 ) + { + i -= 1; + RemoveEntry( aOldPart->m_aliases[ i ] ); + } + + LIB_PART* my_part = new LIB_PART( *aNewPart, this ); + + // Add new aliases to library alias map. + for( i = 0; i < my_part->m_aliases.size(); i++ ) + { + wxString aname = my_part->m_aliases[ i ]->GetName(); + m_amap[ aname ] = my_part->m_aliases[ i ]; + } + + isModified = true; + ++m_mod_hash; + return my_part; +} + + +LIB_ALIAS* PART_LIB::GetNextEntry( const wxString& aName ) +{ + if( m_amap.empty() ) + return NULL; + + LIB_ALIAS_MAP::iterator it = m_amap.find( aName ); + + it++; + + if( it == m_amap.end() ) + it = m_amap.begin(); + + return it->second; +} + + +LIB_ALIAS* PART_LIB::GetPreviousEntry( const wxString& aName ) +{ + if( m_amap.empty() ) + return NULL; + + LIB_ALIAS_MAP::iterator it = m_amap.find( aName ); + + if( it == m_amap.begin() ) + it = m_amap.end(); + + it--; + + return it->second; +} + + +bool PART_LIB::Load( wxString& aErrorMsg ) +{ + FILE* file; + char* line; + wxString msg; + + if( fileName.GetFullPath().IsEmpty() ) + { + aErrorMsg = _( "The component library file name is not set." ); + return false; + } + + file = wxFopen( fileName.GetFullPath(), wxT( "rt" ) ); + + if( file == NULL ) + { + aErrorMsg = _( "The file could not be opened." ); + return false; + } + + FILE_LINE_READER reader( file, fileName.GetFullPath() ); + + if( !reader.ReadLine() ) + { + aErrorMsg = _( "The file is empty!" ); + return false; + } + + // There is no header if this is a symbol library. + if( type == LIBRARY_TYPE_EESCHEMA ) + { + line = reader.Line(); + + header = FROM_UTF8( line ); + + wxStringTokenizer tkn( header ); + + /* + * The file header (first line) in library versions 2.0 and lower + * apparently started with EESchema-LIB. Sometime after 2.0, it + * was changed to EESchema-LIBRARY. Therefore, the test for + * EESchema-LIB will work in both cases. Don't change this unless + * backwards compatibility is no longer required. + */ + if( !tkn.HasMoreTokens() + || !tkn.GetNextToken().Upper().StartsWith(wxT( "EESCHEMA-LIB" ) ) ) + { + aErrorMsg = _( "The file is NOT an Eeschema library!" ); + return false; + } + + if( !tkn.HasMoreTokens() ) + { + aErrorMsg = _( "The file header is missing version and time stamp information." ); + return false; + } + + if( tkn.GetNextToken() != wxT( "Version" ) || !tkn.HasMoreTokens() ) + { + aErrorMsg = wxT( "The file header version information is invalid." ); + return false; + } + + long major, minor; + wxStringTokenizer vers( tkn.GetNextToken(), wxT( "." ) ); + + if( !vers.HasMoreTokens() || !vers.GetNextToken().ToLong( &major ) + || major < 1L || !vers.HasMoreTokens() + || !vers.GetNextToken().ToLong( & minor ) || minor < 0L + || minor > 99 ) + { +#if 0 // Note for developers: + // Not sure this warning is very useful: old designs *must* be always loadable + wxLogWarning( wxT( + "The component library '%s' header version " + "number is invalid.\n\nIn future versions of Eeschema this library may not " + "load correctly. To resolve this problem open the library in the library " + "editor and save it. If this library is the project cache library, save " + "the current schematic." ), + GetChars( GetName() ) ); +#endif + } + else + { + versionMajor = (int) major; + versionMinor = (int) minor; + } + } + + while( reader.ReadLine() ) + { + line = reader.Line(); + + if( type == LIBRARY_TYPE_EESCHEMA && strnicmp( line, "$HEADER", 7 ) == 0 ) + { + if( !LoadHeader( reader ) ) + { + aErrorMsg = _( "An error occurred attempting to read the header." ); + return false; + } + + continue; + } + + if( strnicmp( line, "DEF", 3 ) == 0 ) + { + // Read one DEF/ENDDEF part entry from library: + LIB_PART* part = new LIB_PART( wxEmptyString, this ); + + if( part->Load( reader, msg ) ) + { + // Check for duplicate entry names and warn the user about + // the potential conflict. + if( FindEntry( part->GetName() ) != NULL ) + { + wxString msg = duplicate_name_msg; + + wxLogWarning( msg, + GetChars( fileName.GetName() ), + GetChars( part->GetName() ) ); + } + + LoadAliases( part ); + } + else + { + wxLogWarning( _( "Library '%s' component load error %s." ), + GetChars( fileName.GetName() ), + GetChars( msg ) ); + msg.Clear(); + delete part; + } + } + } + + ++m_mod_hash; + + return true; +} + + +void PART_LIB::LoadAliases( LIB_PART* aPart ) +{ + wxCHECK_RET( aPart, wxT( "Cannot load aliases of NULL part. Bad programmer!" ) ); + + for( size_t i = 0; i < aPart->m_aliases.size(); i++ ) + { + if( FindEntry( aPart->m_aliases[i]->GetName() ) != NULL ) + { + wxString msg = duplicate_name_msg; + + wxLogError( msg, + GetChars( fileName.GetName() ), + GetChars( aPart->m_aliases[i]->GetName() ) ); + } + + wxString aname = aPart->m_aliases[i]->GetName(); + m_amap[ aname ] = aPart->m_aliases[i]; + } +} + + +bool PART_LIB::LoadHeader( LINE_READER& aLineReader ) +{ + char* line, * text, * data; + + while( aLineReader.ReadLine() ) + { + line = (char*) aLineReader; + + text = strtok( line, " \t\r\n" ); + data = strtok( NULL, " \t\r\n" ); + + if( stricmp( text, "TimeStamp" ) == 0 ) + timeStamp = atol( data ); + + if( stricmp( text, "$ENDHEADER" ) == 0 ) + return true; + } + + return false; +} + + +bool PART_LIB::LoadDocs( wxString& aErrorMsg ) +{ + int lineNumber = 0; + char line[8000], * name, * text; + LIB_ALIAS* entry; + FILE* file; + wxFileName fn = fileName; + + fn.SetExt( DOC_EXT ); + + file = wxFopen( fn.GetFullPath(), wxT( "rt" ) ); + + if( file == NULL ) + { + aErrorMsg.Printf( _( "Could not open component document library file '%s'." ), + GetChars( fn.GetFullPath() ) ); + return false; + } + + if( GetLine( file, line, &lineNumber, sizeof(line) ) == NULL ) + { + aErrorMsg.Printf( _( "Part document library file '%s' is empty." ), + GetChars( fn.GetFullPath() ) ); + fclose( file ); + return false; + } + + if( strnicmp( line, DOCFILE_IDENT, 10 ) != 0 ) + { + aErrorMsg.Printf( _( "File '%s' is not a valid component library document file." ), + GetChars( fn.GetFullPath() ) ); + fclose( file ); + return false; + } + + while( GetLine( file, line, &lineNumber, sizeof(line) ) ) + { + if( strncmp( line, "$CMP", 4 ) != 0 ) + { + aErrorMsg.Printf( wxT( "$CMP command expected in line %d, aborted." ), lineNumber ); + fclose( file ); + return false; + } + + // Read one $CMP/$ENDCMP part entry from library: + name = strtok( line + 5, "\n\r" ); + + wxString cmpname = FROM_UTF8( name ); + + entry = FindEntry( cmpname ); + + while( GetLine( file, line, &lineNumber, sizeof(line) ) ) + { + if( strncmp( line, "$ENDCMP", 7 ) == 0 ) + break; + + text = strtok( line + 2, "\n\r" ); + + if( entry ) + { + switch( line[0] ) + { + case 'D': + entry->SetDescription( FROM_UTF8( text ) ); + break; + + case 'K': + entry->SetKeyWords( FROM_UTF8( text ) ); + break; + + case 'F': + entry->SetDocFileName( FROM_UTF8( text ) ); + break; + } + } + } + } + + fclose( file ); + return true; +} + + +bool PART_LIB::Save( OUTPUTFORMATTER& aFormatter ) +{ + if( isModified ) + { + timeStamp = GetNewTimeStamp(); + isModified = false; + } + + bool success = true; + + try + { + SaveHeader( aFormatter ); + + for( LIB_ALIAS_MAP::iterator it=m_amap.begin(); it!=m_amap.end(); it++ ) + { + if( !it->second->IsRoot() ) + continue; + + it->second->GetPart()->Save( aFormatter ); + } + + aFormatter.Print( 0, "#\n#End Library\n" ); + } + catch( const IO_ERROR& ioe ) + { + success = false; + } + + return success; +} + + +bool PART_LIB::SaveDocs( OUTPUTFORMATTER& aFormatter ) +{ + bool success = true; + + try + { + aFormatter.Print( 0, "%s\n", DOCFILE_IDENT ); + + for( LIB_ALIAS_MAP::iterator it=m_amap.begin(); it!=m_amap.end(); it++ ) + { + if( !it->second->SaveDoc( aFormatter ) ) + success = false; + } + + aFormatter.Print( 0, "#\n#End Doc Library\n" ); + } + catch( const IO_ERROR& ioe ) + { + success = false; + } + + return success; +} + + +bool PART_LIB::SaveHeader( OUTPUTFORMATTER& aFormatter ) +{ + aFormatter.Print( 0, "%s %d.%d\n", LIBFILE_IDENT, + LIB_VERSION_MAJOR, LIB_VERSION_MINOR ); + + aFormatter.Print( 0, "#encoding utf-8\n"); + +#if 0 + aFormatter.Print( 0, "$HEADER\n" ); + aFormatter.Print( 0, "TimeStamp %8.8lX\n", m_TimeStamp ); + aFormatter.Print( 0, "Parts %d\n", m_amap.size() ); + aFormatter.Print( 0, "$ENDHEADER\n" ) != 1 ); +#endif + + return true; +} + + +PART_LIB* PART_LIB::LoadLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer ) +{ + std::auto_ptr lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) ); + + wxBusyCursor ShowWait; + + wxString errorMsg; + + if( !lib->Load( errorMsg ) ) + THROW_IO_ERROR( errorMsg ); + + if( USE_OLD_DOC_FILE_FORMAT( lib->versionMajor, lib->versionMinor ) ) + { +#if 1 + // not fatal if error here. + lib->LoadDocs( errorMsg ); +#else + if( !lib->LoadDocs( errorMsg ) ) + THROW_IO_ERROR( errorMsg ); +#endif + } + + PART_LIB* ret = lib.release(); + + return ret; +} + + +PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer ) +{ + PART_LIB* lib; + +#if 1 + wxFileName fn = aFileName; + // Don't reload the library if it is already loaded. + lib = FindLibrary( fn.GetName() ); + if( lib ) + return lib; +#endif + + lib = PART_LIB::LoadLibrary( aFileName ); + + push_back( lib ); + + return lib; +} + + +PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator ) + throw( IO_ERROR, boost::bad_pointer ) +{ +#if 1 + // Don't reload the library if it is already loaded. + wxFileName fn( aFileName ); + PART_LIB* lib = FindLibrary( fn.GetName() ); + + if( lib ) + return lib; +#endif + + lib = PART_LIB::LoadLibrary( aFileName ); + + if( aIterator >= begin() && aIterator < end() ) + insert( aIterator, lib ); + else + push_back( lib ); + + return lib; +} + + +void PART_LIBS::RemoveLibrary( const wxString& aName ) +{ + if( aName.IsEmpty() ) + return; + + for( PART_LIBS::iterator it = begin(); it < end(); ++it ) + { + if( it->GetName().CmpNoCase( aName ) == 0 ) + { + erase( it ); + return; + } + } +} + + +PART_LIB* PART_LIBS::FindLibrary( const wxString& aName ) +{ + for( PART_LIBS::iterator it = begin(); it!=end(); ++it ) + { + if( it->GetName() == aName ) + return &*it; + } + + return NULL; +} + + +wxArrayString PART_LIBS::GetLibraryNames( bool aSorted ) +{ + wxArrayString cacheNames; + wxArrayString names; + + BOOST_FOREACH( PART_LIB& lib, *this ) + { + if( lib.IsCache() && aSorted ) + cacheNames.Add( lib.GetName() ); + else + names.Add( lib.GetName() ); + } + + // Even sorted, the cache library is always at the end of the list. + if( aSorted ) + names.Sort(); + + for( unsigned int i = 0; i& aEntries ) +{ + BOOST_FOREACH( PART_LIB& lib, *this ) + { + LIB_ALIAS* entry = lib.FindEntry( aEntryName ); + + if( entry ) + aEntries.push_back( entry ); + } +} + +/* searches all libraries in the list for an entry, using a case insensitive comparison. + * Used to find an entry, when the normal (case sensitive) search fails. + */ +void PART_LIBS::FindLibraryNearEntries( std::vector& aCandidates, + const wxString& aEntryName, + const wxString& aLibraryName ) +{ + BOOST_FOREACH( PART_LIB& lib, *this ) + { + if( !!aLibraryName && lib.GetName() != aLibraryName ) + continue; + + LIB_ALIAS* entry = lib.GetFirstEntry(); + + if( ! entry ) + continue; + + wxString first_entry_name = entry->GetName(); + wxString entry_name = first_entry_name; + + for( ;; ) + { + if( entry_name.CmpNoCase( aEntryName ) == 0 ) + aCandidates.push_back( entry ); + + entry = lib.GetNextEntry( entry_name ); + entry_name = entry->GetName(); + + if( first_entry_name == entry_name ) + break; + } + } +} + + +int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up + + +int PART_LIBS::GetModifyHash() +{ + int hash = 0; + + for( PART_LIBS::const_iterator it = begin(); it != end(); ++it ) + { + hash += it->m_mod_hash; + } + + return hash; +} + + +/* +void PART_LIBS::RemoveCacheLibrary() +{ + for( PART_LIBS::iterator it = begin(); it < end(); ++it ) + { + if( it->IsCache() ) + erase( it-- ); + } +} +*/ + + +void PART_LIBS::LibNamesAndPaths( PROJECT* aProject, bool doSave, + wxString* aPaths, wxArrayString* aNames ) + throw( IO_ERROR, boost::bad_pointer ) +{ + wxString pro = aProject->GetProjectFullName(); + + PARAM_CFG_ARRAY ca; + + if( aPaths ) + ca.push_back( new PARAM_CFG_FILENAME( wxT( "LibDir" ), aPaths ) ); + + if( aNames ) + ca.push_back( new PARAM_CFG_LIBNAME_LIST( wxT( "LibName" ), aNames, GROUP_SCH_LIBS ) ); + + if( doSave ) + { + aProject->ConfigSave( Kiface().KifaceSearch(), GROUP_SCH, ca ); + + /* + { + wxString msg = wxString::Format( _( + "Unable save project's '%s' file" ), + GetChars( pro ) + ); + THROW_IO_ERROR( msg ); + } + */ + } + else + { + if( !aProject->ConfigLoad( Kiface().KifaceSearch(), GROUP_SCH, ca ) ) + { + wxString msg = wxString::Format( _( + "Unable to load project's '%s' file" ), + GetChars( pro ) + ); + THROW_IO_ERROR( msg ); + } + } +} + + +const wxString PART_LIBS::CacheName( const wxString& aFullProjectFilename ) +{ + /* until apr 2009 the project cache lib was named: .cache.lib, + * and after: -cache.lib. So if the -cache.lib is not found, + * the old file will be renamed and returned. + */ + wxFileName new_name = aFullProjectFilename; + + new_name.SetName( new_name.GetName() + wxT( "-cache" ) ); + new_name.SetExt( SchematicLibraryFileExtension ); + + if( new_name.FileExists() ) + return new_name.GetFullPath(); + else + { + wxFileName old_name = aFullProjectFilename; + old_name.SetExt( wxT( "cache.lib" ) ); + + if( old_name.FileExists() ) + { + wxRenameFile( old_name.GetFullPath(), new_name.GetFullPath() ); + return new_name.GetFullPath(); + } + } + return wxEmptyString; +} + + +void PART_LIBS::LoadAllLibraries( PROJECT* aProject ) throw( IO_ERROR, boost::bad_pointer ) +{ + wxFileName fn; + wxString filename; + wxString libs_not_found; + SEARCH_STACK* lib_search = aProject->SchSearchS(); + +#if defined(DEBUG) && 1 + lib_search->Show( __func__ ); +#endif + + wxArrayString lib_names; + + LibNamesAndPaths( aProject, false, NULL, &lib_names ); + + // If the list is empty, force loading the standard power symbol library. + if( !lib_names.GetCount() ) + lib_names.Add( wxT( "power" ) ); + + wxASSERT( !size() ); // expect to load into "this" empty container. + + for( unsigned i = 0; i < lib_names.GetCount(); ++i ) + { + fn.Clear(); + fn.SetName( lib_names[i] ); + fn.SetExt( SchematicLibraryFileExtension ); + + // Skip if the file name is not valid.. + if( !fn.IsOk() ) + continue; + + if( !fn.FileExists() ) + { + filename = lib_search->FindValidPath( fn.GetFullPath() ); + + if( !filename ) + { + libs_not_found += fn.GetName(); + libs_not_found += wxT( '\n' ); + continue; + } + } + else + { + filename = fn.GetFullPath(); + } + + try + { + AddLibrary( filename ); + } + catch( const IO_ERROR& ioe ) + { + wxString msg = wxString::Format( _( + "Part library '%s' failed to load. Error:\n" + "%s" ), + GetChars( filename ), + GetChars( ioe.errorText ) + ); + + THROW_IO_ERROR( msg ); + } + } + + // add the special cache library. + wxString cache_name = CacheName( aProject->GetProjectFullName() ); + PART_LIB* cache_lib; + + if( !!cache_name ) + { + try + { + cache_lib = AddLibrary( cache_name ); + if( cache_lib ) + cache_lib->SetCache(); + } + catch( const IO_ERROR& ioe ) + { + wxString msg = wxString::Format( _( + "Part library '%s' failed to load.\nError: %s" ), + GetChars( cache_name ), + GetChars( ioe.errorText ) + ); + + THROW_IO_ERROR( msg ); + } + } + + // Print the libraries not found + if( !!libs_not_found ) + { + // Use a different exception type so catch()er can route to proper use + // of the HTML_MESSAGE_BOX. + THROW_PARSE_ERROR( wxEmptyString, UTF8( __func__ ), + UTF8( libs_not_found ), 0, 0 ); + } + +#if defined(DEBUG) && 1 + printf( "%s: lib_names:\n", __func__ ); + + for( PART_LIBS::const_iterator it = begin(); it < end(); ++it ) + printf( " %s\n", TO_UTF8( it->GetName() ) ); +#endif +} diff --git a/eeschema/class_library.h b/eeschema/class_library.h new file mode 100644 index 00000000..37bf0ddd --- /dev/null +++ b/eeschema/class_library.h @@ -0,0 +1,670 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_library.h + * @brief Definition for part library class. + */ + +#ifndef CLASS_LIBRARY_H +#define CLASS_LIBRARY_H + +#include + +#include + +#include + +class LINE_READER; +class OUTPUTFORMATTER; + + +/* + * Part Library version and file header macros. + */ +#define LIB_VERSION_MAJOR 2 +#define LIB_VERSION_MINOR 3 + +/* Must be the first line of part library (.lib) files. */ +#define LIBFILE_IDENT "EESchema-LIBRARY Version" + +#define LIB_VERSION( major, minor ) ( major * 100 + minor ) + +#define IS_LIB_CURRENT_VERSION( major, minor ) \ + ( \ + LIB_VERSION( major1, minor1 ) == \ + LIB_VERSION( LIB_VERSION_MAJOR, LIB_VERSION_MINOR) \ + ) + +/* + * Library versions 2.3 and lower use the old separate library (.lib) and + * document (.dcm) files. Part libraries after 2.3 merged the library + * and document files into a single library file. This macro checks if the + * library version supports the old format + */ +#define USE_OLD_DOC_FILE_FORMAT( major, minor ) \ + ( LIB_VERSION( major, minor ) <= LIB_VERSION( 2, 3 ) ) + +/* Must be the first line of part library document (.dcm) files. */ +#define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0" + +#define DOC_EXT wxT( "dcm" ) + +// Helper class to filter a list of libraries, and/or a list of PART_LIB +// in dialogs +class SCHLIB_FILTER +{ + wxArrayString m_allowedLibs; ///< a list of lib names to list some libraries + ///< if empty: no filter + bool m_filterPowerParts; ///< true to filter (show only) power parts + bool m_forceLoad; // When true, load a part lib from the lib + // which is given in m_allowedLibs[0] + +public: + SCHLIB_FILTER() + { + m_filterPowerParts = false; + m_forceLoad = false; + } + + /** + * add a lib name to the allowed libraries + */ + void AddLib( const wxString& aLibName ) + { + m_allowedLibs.Add( aLibName ); + m_forceLoad = false; + } + + + /** + * add a lib name to the allowed libraries + */ + void LoadFrom( const wxString& aLibName ) + { + m_allowedLibs.Clear(); + m_allowedLibs.Add( aLibName ); + m_forceLoad = true; + } + + /** + * Clear the allowed libraries list (allows all libs) + */ + void ClearLibList() + { + m_allowedLibs.Clear(); + m_forceLoad = false; + } + + /** + * set the filtering of power parts + */ + void FilterPowerParts( bool aFilterEnable ) + { + m_filterPowerParts = aFilterEnable; + } + + // Accessors + + /** + * Function GetFilterPowerParts + * @return true if the filtering of power parts is on + */ + bool GetFilterPowerParts() const { return m_filterPowerParts; } + + + /** + * Function GetAllowedLibList + * @return am wxArrayString of the names of allowed libs + */ + const wxArrayString& GetAllowedLibList() const { return m_allowedLibs; } + + /** + * Function GetLibSource + * @return the name of the lib to use to load a part, or an a emty string + * Useful to load (in lib editor or lib viewer) a part from a given library + */ + const wxString& GetLibSource() const + { + static wxString dummy; + + if( m_forceLoad && m_allowedLibs.GetCount() > 0 ) + return m_allowedLibs[0]; + else + return dummy; + } +}; + + +/* Helpers for creating a list of part libraries. */ +class PART_LIB; +class wxRegEx; + +/** + * LIB_ALIAS map sorting. + */ +struct AliasMapSort +{ + bool operator() ( const wxString& aItem1, const wxString& aItem2 ) const + { + return Cmp_KEEPCASE( aItem1, aItem2 ) < 0; + } +}; + +/// Alias map used by part library object. + +typedef std::map< wxString, LIB_ALIAS*, AliasMapSort > LIB_ALIAS_MAP; +typedef std::vector< LIB_ALIAS* > LIB_ALIASES; +typedef boost::ptr_vector< PART_LIB > PART_LIBS_BASE; + + +/** + * Class PART_LIBS + * is a collection of PART_LIBs. It extends from PROJECT::_ELEM so it can be + * hung in the PROJECT. It does not use any UI calls, but rather simply throws + * an IO_ERROR when there is a problem. + */ +class PART_LIBS : public PART_LIBS_BASE, public PROJECT::_ELEM +{ +public: + + static int s_modify_generation; ///< helper for GetModifyHash() + + PART_LIBS() + { + ++s_modify_generation; + } + + /// Return the modification hash for all libraries. The value returned + /// changes on every library modification. + int GetModifyHash(); + + /** + * Function AddLibrary + * allocates and adds a part library to the library list. + * + * @param aFileName - File name object of part library. + * @throw IO_ERROR if there's any problem loading. + */ + PART_LIB* AddLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function AddLibrary + * inserts a part library into the library list. + * + * @param aFileName - File name object of part library. + * @param aIterator - Iterator to insert library in front of. + * @return PART_LIB* - the new PART_LIB, which remains owned by this PART_LIBS container. + * @throw IO_ERROR if there's any problem loading. + */ + PART_LIB* AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator ) + throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function RemoveLibrary + * removes a part library from the library list. + * + * @param aName - Name of part library to remove. + */ + void RemoveLibrary( const wxString& aName ); + + void RemoveAllLibraries() { clear(); } + + /** + * Function LoadAllLibraries + * loads all of the project's libraries into this container, which should + * be cleared before calling it. + */ + void LoadAllLibraries( PROJECT* aProject ) throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function LibNamesAndPaths + * either saves or loads the names of the currently configured part libraries + * (without paths). + */ + static void LibNamesAndPaths( PROJECT* aProject, bool doSave, + wxString* aPaths, wxArrayString* aNames=NULL ) + throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function cacheName + * returns the name of the cache library after potentially fixing it from + * an older naming scheme. That is, the old file is renamed if needed. + * @param aFullProjectFilename - the *.pro filename with absolute path. + */ + static const wxString CacheName( const wxString& aFullProjectFilename ); + + /** + * Function FindLibrary + * finds a part library by \a aName. + * + * @param aName - Library file name without path or extension to find. + * @return Part library if found, otherwise NULL. + */ + PART_LIB* FindLibrary( const wxString& aName ); + + /** + * Function GetLibraryNames + * returns the list of part library file names without path and extension. + * + * @param aSorted - Sort the list of name if true. Otherwise use the + * library load order. + * @return The list of library names. + */ + wxArrayString GetLibraryNames( bool aSorted = true ); + + /** + * Function FindLibPart + * searches all libraries in the list for a part. + * + * A part object will always be returned. If the entry found + * is an alias. The root part will be found and returned. + * + * @param aPartName - Name of part to search for. + * @param aLibraryName - Name of the library to search for part. + * @return LIB_PART* - The part object if found, otherwise NULL. + */ + LIB_PART* FindLibPart( const wxString& aPartName, const wxString& aLibraryName = wxEmptyString ); + + /** + * Function FindLibraryEntry + * searches all libraries in the list for an entry. + * + * The object can be either a part or an alias. + * + * @param aEntryName - Name of entry to search for (case sensitive). + * @param aLibraryName - Name of the library to search. + * @return The entry object if found, otherwise NULL. + */ + LIB_ALIAS* FindLibraryEntry( const wxString& aEntryName, + const wxString& aLibraryName = wxEmptyString ); + + /** + * Function FindLibraryEntries + * searches all libraries in the list for an entry, returns all matches. + * + * @param aEntryName - Name of entry to search for (case sensitive). + * @param aEntries - a std::vector to store entries + */ + void FindLibraryEntries( const wxString& aEntryName, std::vector& aEntries ); + + /** + * Function FindLibraryNearEntries + * Searches all libraries in the list for an entry, using a case insensitive comparison. + * Helper function used in dialog to find all candidates. + * During a long time, eeschema was using a case insensitive search. + * Therefore, for old schematics (<= 2013), or libs, for some components, + * the chip name (name of alias in lib) can be broken. + * This function can be used to display a list of candidates, in component properties dialog. + * + * @param aEntryName - Name of entries to search for (case insensitive). + * @param aLibraryName - Name of the library to search. + * @param aCandidates - a std::vector to store candidates + */ + void FindLibraryNearEntries( std::vector& aCandidates, const wxString& aEntryName, + const wxString& aLibraryName = wxEmptyString ); + + /** + * Function RemoveCacheLibrary + * removes all cache libraries from library list. + */ + //void RemoveCacheLibrary(); + + int GetLibraryCount() { return size(); } + +}; + + +/** + * Class PART_LIB + * is used to load, save, search, and otherwise manipulate + * part library files. + */ +class PART_LIB +{ + int type; ///< Library type indicator. + wxFileName fileName; ///< Library file name. + wxDateTime timeStamp; ///< Library save time and date. + int versionMajor; ///< Library major version number. + int versionMinor; ///< Library minor version number. + bool isCache; /**< False for the "standard" libraries, + True for the library cache */ + wxString header; ///< first line of loaded library. + bool isModified; ///< Library modification status. + LIB_ALIAS_MAP m_amap; ///< Map of alias objects associated with the library. + int m_mod_hash; ///< incremented each time library is changed. + + friend class LIB_PART; + friend class PART_LIBS; + +public: + PART_LIB( int aType, const wxString& aFileName ); + ~PART_LIB(); + + /** + * Function Save + * writes library to \a aFormatter. + * + * @param aFormatter An #OUTPUTFORMATTER object to write the library to. + * @return True if success writing to \a aFormatter. + */ + bool Save( OUTPUTFORMATTER& aFormatter ); + + /** + * Function SaveDocs + * write the library document information to \a aFormatter. + * + * @param aFormatter An #OUTPUTFORMATTER object to write the library documentation to. + * @return True if success writing to \a aFormatter. + */ + bool SaveDocs( OUTPUTFORMATTER& aFormatter ); + + /** + * Load library from file. + * + * @param aErrorMsg - Error message if load fails. + * @return True if load was successful otherwise false. + */ + bool Load( wxString& aErrorMsg ); + + bool LoadDocs( wxString& aErrorMsg ); + +private: + bool SaveHeader( OUTPUTFORMATTER& aFormatter ); + + bool LoadHeader( LINE_READER& aLineReader ); + void LoadAliases( LIB_PART* aPart ); + +public: + /** + * Get library entry status. + * + * @return True if there are no entries in the library. + */ + bool IsEmpty() const + { + return m_amap.empty(); + } + + /** + * Function GetCount + * returns the number of entries in the library. + * + * @return The number of part and alias entries. + */ + int GetCount() const + { + return m_amap.size(); + } + + bool IsModified() const + { + return isModified; + } + + bool IsCache() const { return isCache; } + + void SetCache( void ) { isCache = true; } + + /** + * Function IsReadOnly + * @return true if current user does not have write access to the library file. + */ + bool IsReadOnly() const { return !fileName.IsFileWritable(); } + + /** + * Load a string array with the names of all the entries in this library. + * + * @param aNames - String array to place entry names into. + * @param aSort - Sort names if true. + * @param aMakeUpperCase - Force entry names to upper case. + */ + void GetEntryNames( wxArrayString& aNames, bool aSort = true, + bool aMakeUpperCase = false ); + + /** + * Load a string array with the names of entries of type POWER in this library. + * + * @param aNames - String array to place entry names into. + * @param aSort - Sort names if true. + * @param aMakeUpperCase - Force entry names to upper case. + */ + void GetEntryTypePowerNames( wxArrayString& aNames, bool aSort = true, + bool aMakeUpperCase = false ); + + /** + * Load string array with entry names matching name and/or key word. + * + * This currently mimics the old behavior of calling KeyWordOk() and + * WildCompareString(). The names array will be populated with the + * library entry names that meat the search criteria on exit. + * + * @param aNames - String array to place entry names into. + * @param aNameSearch - Name wild card search criteria. + * @param aKeySearch - Key word search criteria. + * @param aSort - Sort names if true. + */ + void SearchEntryNames( std::vector& aNames, + const wxString& aNameSearch = wxEmptyString, + const wxString& aKeySearch = wxEmptyString, + bool aSort = true ); + + /** + * Find parts in library by key word regular expression search. + * + * @param aNames - String array to place found part names into. + * @param aRe - Regular expression used to search part key words. + * @param aSort - Sort part name list. + */ + void SearchEntryNames( wxArrayString& aNames, const wxRegEx& aRe, bool aSort = true ); + + /** + * Checks \a aPart for name conflict in the library. + * + * @param aPart - The part to check. + * @return True if a conflict exists. Otherwise false. + */ + bool Conflicts( LIB_PART* aPart ); + + /** + * Find entry by name. + * + * @param aName - Name of entry, case sensitive. + * @return Entry if found. NULL if not found. + */ + LIB_ALIAS* FindEntry( const wxString& aName ); + + /** + * Find part by \a aName. + * + * This is a helper for FindEntry so casting a LIB_ALIAS pointer to + * a LIB_PART pointer is not required. + * + * @param aName - Name of part, case sensitive. + * @return LIB_PART* - part if found, else NULL. + */ + LIB_PART* FindPart( const wxString& aName ); + + /** + * Find alias by \a nName. + * + * @param aName - Name of alias, case sensitive. + * @return Alias if found. NULL if not found. + */ + LIB_ALIAS* FindAlias( const wxString& aName ) + { + return (LIB_ALIAS*) FindEntry( aName ); + } + + /** + * Add a new \a aAlias entry to the library. + * + * First check if a part or alias with the same name already exists + * in the library and add alias if no conflict occurs. Once the alias + * is added to the library it is owned by the library. Deleting the + * alias pointer will render the library unstable. Use RemoveEntry to + * remove the alias from the library. + * + * @param aAlias - Alias to add to library. + * @return True if alias added to library. False if a conflict exists. + */ + bool AddAlias( LIB_ALIAS* aAlias ); + + /** + * Add \a aPart entry to library. + * Note a part can have an alias list, + * so these alias will be added in library. + * Conflicts can happen if aliases are already existing. + * User is asked to choose what alias is removed (existing, or new) + * + * @param aPart - Part to add, caller retains ownership, a clone is added. + * @return bool - true iff successful. + */ + bool AddPart( LIB_PART* aPart ); + + /** + * Safely remove \a aEntry from the library and return the next entry. + * + * The next entry returned depends on the entry being removed. If the entry being + * remove also removes the part, then the next entry from the list is returned. + * If the entry being used only removes an alias from a part, then the next alias + * of the part is returned. + * + * @param aEntry - Entry to remove from library. + * @return The next entry in the library or NULL if the library is empty. + */ + LIB_ALIAS* RemoveEntry( LIB_ALIAS* aEntry ); + + /** + * Replace an existing part entry in the library. + * Note a part can have an alias list, + * so these alias will be added in library (and previously existing alias removed) + * @param aOldPart - The part to replace. + * @param aNewPart - The new part. + */ + LIB_PART* ReplacePart( LIB_PART* aOldPart, LIB_PART* aNewPart ); + + /** + * Return the first entry in the library. + * + * @return The first entry or NULL if the library has no entries. + */ + LIB_ALIAS* GetFirstEntry(); + + /** + * Find next library entry by \a aName. + * + * If the name of the entry is the last entry in the library, the first + * entry in the list is returned. + * + * @param aName - Name of current entry. + * @return Next entry if entry name is found. Otherwise NULL. + */ + LIB_ALIAS* GetNextEntry( const wxString& aName ); + + /** + * Find previous library entry by \a aName. + * + * If the name of the entry is the first entry in the library, the last + * entry in the list is returned. + * + * @param aName - Name of current entry. + * @return Previous entry if entry name is found, otherwise NULL. + */ + LIB_ALIAS* GetPreviousEntry( const wxString& aName ); + + /** + * Return the file name without path or extension. + * + * @return Name of library file. + */ + const wxString GetName() const { return fileName.GetName(); } + + /** + * Function GetFullFileName + * returns the full file library name with path and extension. + * + * @return wxString - Full library file name with path and extension. + */ + wxString GetFullFileName() { return fileName.GetFullPath(); } + + /** + * Function GetLogicalName + * returns the logical name of the library. + * @return wxString - The logical name of this library. + */ + const wxString GetLogicalName() + { + /* for now is the filename without path or extension. + + Technically the library should not know its logical name! + This will eventually come out of a pair of lookup tables using a + reverse lookup using the full name or library pointer as a key. + Search will be by project lookup table and then user lookup table if + not found. + */ + return fileName.GetName(); + } + + + /** + * Function SetFileName + * sets the part library file name. + * + * @param aFileName - New library file name. + */ + void SetFileName( const wxString& aFileName ) + { + if( aFileName != fileName.GetFullName() ) + fileName = aFileName; + } + + /** + * Function LoadLibrary + * allocates and loads a part library file. + * + * @param aFileName - File name of the part library to load. + * @return PART_LIB* - the allocated and loaded PART_LIB, which is owned by + * the caller. + * @throw IO_ERROR if there's any problem loading the library. + */ + static PART_LIB* LoadLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function HasPowerParts + * @return true if at least one power part is found in lib + * Useful to select or list only libs containing power parts + */ + bool HasPowerParts(); +}; + + +/** + * Case insensitive library name comparison. + */ +bool operator==( const PART_LIB& aLibrary, const wxString& aName ); +bool operator!=( const PART_LIB& aLibrary, const wxString& aName ); + +#endif // CLASS_LIBRARY_H diff --git a/eeschema/class_netlist_object.cpp b/eeschema/class_netlist_object.cpp new file mode 100644 index 00000000..760af590 --- /dev/null +++ b/eeschema/class_netlist_object.cpp @@ -0,0 +1,423 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2016 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 + */ + +/** + * @file class_netlist_object.cpp + * @brief Class NETLIST_OBJECT to handle 1 item connected (in netlist and erc calculations) + */ + +#include +#include +#include + +#include +#include + +#include + + +/** + * The regular expression string for label bus notation. Valid bus labels are defined as + * one or more non-whitespace characters from the beginning of the string followed by the + * bus notation [nn...mm] with no characters after the closing bracket. + */ +static wxRegEx busLabelRe( wxT( "^([^[:space:]]+)(\\[[\\d]+\\.+[\\d]+\\])$" ), wxRE_ADVANCED ); + + +bool IsBusLabel( const wxString& aLabel ) +{ + wxCHECK_MSG( busLabelRe.IsValid(), false, + wxT( "Invalid regular expression in IsBusLabel()." ) ); + + return busLabelRe.Matches( aLabel ); +} + + +#if defined(DEBUG) + +#include +const char* ShowType( NETLIST_ITEM_T aType ) +{ + const char* ret; + + switch( aType ) + { + case NET_SEGMENT: + ret = "segment"; break; + + case NET_BUS: + ret = "bus"; break; + + case NET_JUNCTION: + ret = "junction"; break; + + case NET_LABEL: + ret = "label"; break; + + case NET_HIERLABEL: + ret = "hierlabel"; break; + + case NET_GLOBLABEL: + ret = "glabel"; break; + + case NET_BUSLABELMEMBER: + ret = "buslblmember"; break; + + case NET_HIERBUSLABELMEMBER: + ret = "hierbuslblmember"; break; + + case NET_GLOBBUSLABELMEMBER: + ret = "gbuslblmember"; break; + + case NET_SHEETBUSLABELMEMBER: + ret = "sbuslblmember"; break; + + case NET_SHEETLABEL: + ret = "sheetlabel"; break; + + case NET_PINLABEL: + ret = "pinlabel"; break; + + case NET_PIN: + ret = "pin"; break; + + case NET_NOCONNECT: + ret = "noconnect"; break; + + default: + ret = "??"; break; + } + + return ret; +} + + +void NETLIST_OBJECT::Show( std::ostream& out, int ndx ) const +{ + wxString path = m_SheetPath.PathHumanReadable(); + + out << "\n"; + + out << " \n"; + + if( !m_Label.IsEmpty() ) + out << " \n"; + + out << " " << m_SheetPath.PathHumanReadable().mb_str() << "\n"; + + switch( m_Type ) + { + case NET_PIN: + /* GetRef() needs to be const + out << " " << GetComponentParent()->GetRef(&m_SheetPath).mb_str() + << "\n"; + */ + + if( m_Comp ) + m_Comp->Show( 1, out ); + + break; + + default: + // not all the m_Comp classes have working Show functions. + ; + } + +/* was segfault-ing + if( m_Comp ) + m_Comp->Show( 1, out ); // labels may not have good Show() funcs? + else + out << " m_Comp==NULL\n"; +*/ + + out << "\n"; +} + +#endif + + +NETLIST_OBJECT::NETLIST_OBJECT() +{ + m_Type = NET_ITEM_UNSPECIFIED; /* Type of this item (see NETLIST_ITEM_T enum) */ + m_Comp = NULL; /* Pointer on the library item that created this net object + * (the parent)*/ + m_Link = NULL; /* For SCH_SHEET_PIN: + * Pointer to the hierarchy sheet that contains this + * SCH_SHEET_PIN For Pins: pointer to the component that + * contains this pin + */ + m_Flag = 0; /* flag used in calculations */ + m_ElectricalType = 0; /* Has meaning only for Pins and hierarchical pins: electrical + * type */ + m_netCode = 0; /* net code for all items except BUS labels because a BUS + * label has as many net codes as bus members + */ + m_BusNetCode = 0; /* Used for BUS connections */ + m_Member = 0; /* for labels type NET_BUSLABELMEMBER ( bus member created + * from the BUS label ) member number + */ + m_ConnectionType = UNCONNECTED; + m_PinNum = 0; /* pin number ( 1 long = 4 bytes -> 4 ascii codes) */ + m_netNameCandidate = NULL; /* a pointer to a NETLIST_OBJECT type label connected to this + * object used to give a name to the net + */ +} + + +// Copy constructor +NETLIST_OBJECT::NETLIST_OBJECT( NETLIST_OBJECT& aSource ) +{ + *this = aSource; +} + + +NETLIST_OBJECT::~NETLIST_OBJECT() +{ +} + + +// return true if the object is a label of any type +bool NETLIST_OBJECT::IsLabelType() const +{ + return m_Type == NET_LABEL + || m_Type == NET_GLOBLABEL || m_Type == NET_HIERLABEL + || m_Type == NET_BUSLABELMEMBER || m_Type == NET_GLOBBUSLABELMEMBER + || m_Type == NET_HIERBUSLABELMEMBER + || m_Type == NET_PINLABEL; +} + +bool NETLIST_OBJECT::IsLabelConnected( NETLIST_OBJECT* aNetItem ) +{ + if( aNetItem == this ) // Don't compare the same net list object. + return false; + + int at = m_Type; + int bt = aNetItem->m_Type; + + if( ( at == NET_HIERLABEL || at == NET_HIERBUSLABELMEMBER ) + && ( bt == NET_SHEETLABEL || bt == NET_SHEETBUSLABELMEMBER ) ) + { + if( m_SheetPath == aNetItem->m_SheetPathInclude ) + { + return true; //connected! + } + } + else if( ( at == NET_GLOBLABEL ) && ( bt == NET_GLOBLABEL ) ) + { + if( m_Label == aNetItem->m_Label ) + return true; //connected! + } + + return false; //these two are unconnected +} + + +void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems ) +{ + wxCHECK_RET( IsBusLabel( m_Label ), + wxT( "<" ) + m_Label + wxT( "> is not a valid bus label." ) ); + + if( m_Type == NET_HIERLABEL ) + m_Type = NET_HIERBUSLABELMEMBER; + else if( m_Type == NET_GLOBLABEL ) + m_Type = NET_GLOBBUSLABELMEMBER; + else if( m_Type == NET_SHEETLABEL ) + m_Type = NET_SHEETBUSLABELMEMBER; + else if( m_Type == NET_LABEL ) + m_Type = NET_BUSLABELMEMBER; + else + wxCHECK_RET( false, wxT( "Net list object type is not valid." ) ); + + unsigned i; + wxString tmp, busName, busNumber; + long begin, end, member; + + busName = busLabelRe.GetMatch( m_Label, 1 ); + busNumber = busLabelRe.GetMatch( m_Label, 2 ); + + /* Search for '[' because a bus label is like "busname[nn..mm]" */ + i = busNumber.Find( '[' ); + i++; + + while( i < busNumber.Len() && busNumber[i] != '.' ) + { + tmp.Append( busNumber[i] ); + i++; + } + + tmp.ToLong( &begin ); + + while( i < busNumber.Len() && busNumber[i] == '.' ) + i++; + + tmp.Empty(); + + while( i < busNumber.Len() && busNumber[i] != ']' ) + { + tmp.Append( busNumber[i] ); + i++; + } + + tmp.ToLong( &end ); + + if( begin < 0 ) + begin = 0; + + if( end < 0 ) + end = 0; + + if( begin > end ) + std::swap( begin, end ); + + member = begin; + tmp = busName; + tmp << member; + m_Label = tmp; + m_Member = member; + + for( member++; member <= end; member++ ) + { + NETLIST_OBJECT* item = new NETLIST_OBJECT( *this ); + + // Conversion of bus label to the root name + the current member id. + tmp = busName; + tmp << member; + item->m_Label = tmp; + item->m_Member = member; + + aNetListItems.push_back( item ); + } +} + + +bool NETLIST_OBJECT::IsLabelGlobal() const +{ + // return true if the object is a global label + // * a actual global label + // * a pin label coming from a invisible power pin + return ( m_Type == NET_PINLABEL ) || + ( m_Type == NET_GLOBLABEL ) || + ( m_Type == NET_GLOBBUSLABELMEMBER ); +} + + +bool NETLIST_OBJECT::IsLabelBusMemberType() const +{ + // return true if the object is a bus label member build from a + // schematic bus label (like label[xx..yy) + // They are labels with very specific properties, especially for connection + // between them: 2 bus label members can be connected only + // if they have the same member value. + return ( m_Type == NET_SHEETBUSLABELMEMBER ) || + ( m_Type == NET_BUSLABELMEMBER ) || + ( m_Type == NET_HIERBUSLABELMEMBER ) || + ( m_Type == NET_GLOBBUSLABELMEMBER ); +} + + +/* + * return the net name of the item + */ +wxString NETLIST_OBJECT::GetNetName() const +{ + if( m_netNameCandidate == NULL ) + return wxEmptyString; + + wxString netName; + + if( m_netNameCandidate->m_Type == NET_PIN ) + return GetShortNetName(); + + if( !m_netNameCandidate->IsLabelGlobal() ) + { + // usual net name, prefix it by the sheet path + netName = m_netNameCandidate->m_SheetPath.PathHumanReadable(); + } + + netName += m_netNameCandidate->m_Label; + + return netName; +} + +/** + * return the short net name of the item i.e. the net name + * from the "best" label without any prefix. + * 2 different nets can have the same short name + */ +wxString NETLIST_OBJECT::GetShortNetName() const +{ + if( m_netNameCandidate == NULL ) + return wxEmptyString; + + wxString netName; + + if( m_netNameCandidate->m_Type == NET_PIN ) + { + SCH_COMPONENT* link = m_netNameCandidate->GetComponentParent(); + if( link ) // Should be always true + { + netName = wxT("Net-("); + netName << link->GetRef( &m_netNameCandidate->m_SheetPath ); + netName << wxT("-Pad") + << LIB_PIN::PinStringNum( m_netNameCandidate->m_PinNum ) + << wxT(")"); + } + } + else + netName = m_netNameCandidate->m_Label; + + return netName; +} + +/** + * Set m_netNameCandidate to a connected item which will + * be used to calcule the net name of the item + * Obviously the candidate can be only a label + * If there is no label on the net, a pad name will be + * used to build a net name (something like Cmp_Pad + * @param aCandidate = the connected item candidate + */ +void NETLIST_OBJECT::SetNetNameCandidate( NETLIST_OBJECT* aCandidate ) +{ + switch( aCandidate->m_Type ) + { + case NET_HIERLABEL: + case NET_LABEL: + case NET_PINLABEL: + case NET_GLOBLABEL: + case NET_GLOBBUSLABELMEMBER: + case NET_SHEETBUSLABELMEMBER: + case NET_PIN: + m_netNameCandidate = aCandidate; + break; + + default: + break; + } +} diff --git a/eeschema/class_netlist_object.h b/eeschema/class_netlist_object.h new file mode 100644 index 00000000..3e726d45 --- /dev/null +++ b/eeschema/class_netlist_object.h @@ -0,0 +1,483 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2013 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 + */ + +/** + * @file class_netlist_object.h + * @brief Definition of the NETLIST_OBJECT class. + */ + +#ifndef _CLASS_NETLIST_OBJECT_H_ +#define _CLASS_NETLIST_OBJECT_H_ + + +#include +#include // LIB_PIN::PinStringNum( m_PinNum ) +#include + +class NETLIST_OBJECT_LIST; +class SCH_COMPONENT; + + +/* Type of Net objects (wires, labels, pins...) */ +enum NETLIST_ITEM_T +{ + NET_ITEM_UNSPECIFIED, // only for not yet initialized instances + NET_SEGMENT, // connection by wire + NET_BUS, // connection by bus + NET_JUNCTION, // connection by junction: can connect to + // or more crossing wires + NET_LABEL, // this is a local label + NET_GLOBLABEL, // this is a global label that connect all + // others global label in whole hierarchy + NET_HIERLABEL, // element to indicate connection to a + // higher-level sheet + NET_SHEETLABEL, // element to indicate connection to a + // lower-level sheet. + NET_BUSLABELMEMBER, /* created when a bus label is found: + * the bus label (like DATA[0..7] is + * converted to n single labels like + * DATA0, DATA1 ... + * These objects are living only in the current + * NETLIST_OBJECT_LIST, not in shematic. + */ + NET_GLOBBUSLABELMEMBER, // see NET_BUSLABELMEMBER, used when a + // global bus label is found + NET_HIERBUSLABELMEMBER, // see NET_BUSLABELMEMBER, used when a + // hierarchical bus label is found + NET_SHEETBUSLABELMEMBER, // see NET_BUSLABELMEMBER, used when a + // pin sheet label using bus notation + // is found + NET_PINLABEL, /* created when a pin is POWER (IN or + * OUT) with invisible attribute is found: + * these pins are equivalent to a global + * label and are automatically connected + */ + NET_PIN, // this is an usual pin + NET_NOCONNECT // this is a no connect symbol +}; + + +/* Values for .m_FlagOfConnection member */ +enum NET_CONNECTION_T +{ + UNCONNECTED = 0, /* Pin or Label not connected (error) */ + NOCONNECT_SYMBOL_PRESENT, /* Pin not connected but have a NoConnect + * symbol on it (no error) */ + PAD_CONNECT /* Normal connection (no error) */ +}; + + +class NETLIST_OBJECT +{ +public: + NETLIST_ITEM_T m_Type; /* Type of item (see NETLIST_ITEM_T enum) */ + EDA_ITEM* m_Comp; /* Pointer to the library item that + * created this net object (the parent) + */ + SCH_ITEM* m_Link; /* For SCH_SHEET_PIN: + * Pointer to the hierarchy sheet that + * contains this SCH_SHEET_PIN + * For Pins: pointer to the schematic component + * that contains this pin + */ + int m_Flag; /* flag used in calculations */ + SCH_SHEET_PATH m_SheetPath; // the sheet path which contains this item + SCH_SHEET_PATH m_SheetPathInclude; // sheet path which contains the hierarchical label + int m_ElectricalType; /* Has meaning only for Pins and + * hierarchical pins: electrical type */ + int m_BusNetCode; /* Used for BUS connections */ + int m_Member; /* for labels type NET_BUSLABELMEMBER ( bus member + * created from the BUS label ) member number. + */ + NET_CONNECTION_T m_ConnectionType; // Used to store the connection type + long m_PinNum; // pin number ( 1 long = 4 bytes -> 4 ascii codes) + wxString m_Label; // Label text (for labels) or Pin name (for pins) + wxPoint m_Start; // Position of object or for segments: starting point + wxPoint m_End; // For segments (wire and buses): ending point + +private: + int m_netCode; /* net code for all items except BUS + * labels because a BUS label has + * as many net codes as bus members + */ + NETLIST_OBJECT* m_netNameCandidate; /* a pointer to a label connected to the net, + * that can be used to give a name to the net + * or a pin if there is no label in net + * When no label, the pin is used to build + * default net name. + */ + +public: + +#if defined(DEBUG) + void Show( std::ostream& out, int ndx ) const; // override + +#endif + + NETLIST_OBJECT(); + NETLIST_OBJECT( NETLIST_OBJECT& aSource ); // Copy constructor + + ~NETLIST_OBJECT(); + + // Accessors: + void SetNet( int aNetCode ) { m_netCode = aNetCode; } + int GetNet() const { return m_netCode; } + + /** + * Set the item connection type: + * UNCONNECTED Pin or Label not connected (error) + * NOCONNECT_SYMBOL_PRESENT Pin not connected but have a NoConnect + * symbol on it (no error) + * PAD_CONNECT Normal connection (no error) + */ + void SetConnectionType( NET_CONNECTION_T aFlg = UNCONNECTED ) + { + m_ConnectionType = aFlg; + } + + NET_CONNECTION_T GetConnectionType() + { + return m_ConnectionType; + } + + /** + * Set m_netNameCandidate to a connected item which will + * be used to calcule the net name of the item + * Obviously the candidate can be only a label + * when there is no label on the net a pad which will + * used to build a net name (something like Cmp_Pad + * @param aCandidate = the connected item candidate + */ + void SetNetNameCandidate( NETLIST_OBJECT* aCandidate ); + + /** + * @return true if an item has already a net name candidate + * and false if not ( m_netNameCandidate == NULL ) + */ + bool HasNetNameCandidate() { return m_netNameCandidate != NULL; } + + /** + * Function GetPinNum + * returns a pin number in wxString form. Pin numbers are not always + * numbers. \"A23\" would be a valid pin number. + */ + wxString GetPinNumText() + { + // hide the ugliness in here, but do it inline. + return LIB_PIN::PinStringNum( m_PinNum ); + } + + /** For Pins (NET_PINS): + * @return the schematic component which contains this pin + * (Note: this is the schematic component, not the library component + * for others items: return NULL + */ + SCH_COMPONENT* GetComponentParent() const + { + if( m_Link && m_Link->Type() == SCH_COMPONENT_T ) + return (SCH_COMPONENT*) m_Link; + + return NULL; + } + + /** + * Function IsLabelConnected + * tests if the net list object is a hierarchical label or sheet label and is + * connected to an associated hierarchical label or sheet label of \a aNetItem. + * + * @param aNetItem A pointer to a NETLIST_OBJECT to test against. + * @return A bool value of true if there is a connection with \a aNetItem or false + * if no connection to \a aNetItem. + */ + bool IsLabelConnected( NETLIST_OBJECT* aNetItem ); + + /** + * Function IsLabelGlobal + * @return true if the object is a global label + * (i.e. an real global label or a pin label coming + * from a power pin invisible + */ + bool IsLabelGlobal() const; + + /** + * Function IsLabelBusMemberType + * @return true if the object is a bus label member build from a + * schematic bus label (like label[xx..yy], xx and yy are the first and last + * bus member id) + * bus label members have specific properties: + * they do not live in schematic + * they have specific properties in connections: + * 2 bus label members can be connected connected only if they have the same member value. + */ + bool IsLabelBusMemberType() const; + + /** + * Function IsLabelType + * @return true if the object is a label of any type + */ + bool IsLabelType() const; + + /** + * Function GetNetName + * @return the full net name of the item, i.e. the net name + * from the "best" label, prefixed by the sheet path + */ + wxString GetNetName() const; + + /** + * Function GetShortNetName + * @return the short net name of the item i.e. the net name + * from the "best" label without any prefix. + * 2 different nets can have the same short name + */ + wxString GetShortNetName() const; + + /** + * Function ConvertBusToNetListItems + * breaks the text of a bus label type net list object into as many members as + * it contains and creates a #NETLIST_OBJECT for each label and adds it to \a + * aNetListItems. + * + * @param aNetListItems A reference to vector of #NETLIST_OBJECT pointers to add + * the bus label NETLIST_OBJECTs. + */ + void ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems ); +}; + + +/** + * Type NETLIST_OBJECTS + * is a container referring to (not owning) NETLIST_OBJECTs, which are connected items + * in a full schematic hierarchy. It is useful when referring to NETLIST_OBJECTs + * actually owned by some other container. + */ +typedef std::vector NETLIST_OBJECTS; + + +/** + * Class NETLIST_OBJECT_LIST + * is a container holding and _owning_ NETLIST_OBJECTs, which are connected items + * in a full schematic hierarchy. It is helpful for netlist and ERC calculations. + */ +class NETLIST_OBJECT_LIST : public NETLIST_OBJECTS +{ + int m_lastNetCode; // Used in intermediate calculation: last net code created + int m_lastBusNetCode; // Used in intermediate calculation: + // last net code created for bus members + +public: + /** + * Constructor. + * NETLIST_OBJECT_LIST handle a list of connected items. + * the instance can be owner of items or not. + * If it is the owner, the items are freeed by the destructor + * @param aIsOwner true if the instance is the owner of item list + * (default = false) + */ + NETLIST_OBJECT_LIST() + { + // Do not leave some members uninitialized: + m_lastNetCode = 0; + m_lastBusNetCode = 0; + } + + ~NETLIST_OBJECT_LIST(); + + /** + * Function BuildNetListInfo + * the master function of tgis class. + * Build the list of connected objects (pins, labels ...) and + * all info to generate netlists or run ERC diags + * @param aSheets = the flattened sheet list + * @return true if OK, false is not item found + */ + bool BuildNetListInfo( SCH_SHEET_LIST& aSheets ); + + /** + * Acces to an item in list + */ + NETLIST_OBJECT* GetItem( unsigned aIdx ) const + { + return *( this->begin() + aIdx ); + } + + /** + * Acces to an item type + */ + NETLIST_ITEM_T GetItemType( unsigned aIdx ) const + { + return GetItem( aIdx )->m_Type; + } + + /** + * Acces to an item net code + */ + int GetItemNet( unsigned aIdx ) const + { + return GetItem( aIdx )->GetNet(); + } + + NET_CONNECTION_T GetConnectionType( unsigned aIdx ) + { + return GetItem( aIdx )->GetConnectionType(); + } + + /** + * Set the item connection type: + * UNCONNECTED Pin or Label not connected (error) + * NOCONNECT_SYMBOL_PRESENT Pin not connected but have a NoConnect + * symbol on it (no error) + * PAD_CONNECT Normal connection (no error) + */ + void SetConnectionType( unsigned aIdx, NET_CONNECTION_T aFlg = UNCONNECTED ) + { + GetItem( aIdx )->SetConnectionType( aFlg ); + } + + /** Delete all objects in list and clear list */ + void Clear(); + + /** + * Reset the connection type of all items to UNCONNECTED type + */ + void ResetConnectionsType() + { + for( unsigned ii = 0; ii < size(); ii++ ) + GetItem( ii )->SetConnectionType( UNCONNECTED ); + } + + /* + * Sorts the list of connected items by net code + */ + void SortListbyNetcode(); + + /* + * Sorts the list of connected items by sheet. + * This sorting is used when searching "physical" connection between items + * because obviously only items inside the same sheet can be connected + */ + void SortListbySheet(); + + + #if defined(DEBUG) + void DumpNetTable() + { + for( unsigned idx = 0; idx < size(); ++idx ) + { + GetItem( idx )->Show( std::cout, idx ); + } + } + + #endif + +private: + /* + * Propagate aNewNetCode to items having an internal netcode aOldNetCode + * used to interconnect group of items already physically connected, + * when a new connection is found between aOldNetCode and aNewNetCode + */ + void propageNetCode( int aOldNetCode, int aNewNetCode, bool aIsBus ); + + /* + * This function merges the net codes of groups of objects already connected + * to labels (wires, bus, pins ... ) when 2 labels are equivalents + * (i.e. group objects connected by labels) + */ + void labelConnect( NETLIST_OBJECT* aLabelRef ); + + /* Comparison function to sort by increasing Netcode the list of connected items + */ + static bool sortItemsbyNetcode( const NETLIST_OBJECT* Objet1, const NETLIST_OBJECT* Objet2 ) + { + return Objet1->GetNet() < Objet2->GetNet(); + } + + /* Comparison routine to sort items by Sheet Number + */ + static bool sortItemsBySheet( const NETLIST_OBJECT* Objet1, const NETLIST_OBJECT* Objet2 ) + { + return Objet1->m_SheetPath.Cmp( Objet2->m_SheetPath ) < 0; + } + + /** + * Propagate net codes from a parent sheet to an include sheet, + * from a pin sheet connection + */ + void sheetLabelConnect( NETLIST_OBJECT* aSheetLabel ); + + void pointToPointConnect( NETLIST_OBJECT* aRef, bool aIsBus, int start ); + + /** + * Search connections between a junction and segments + * Propagate the junction net code to objects connected by this junction. + * The junction must have a valid net code + * The list of objects is expected sorted by sheets. + * Search is done from index aIdxStart to the last element of list + */ + void segmentToPointConnect( NETLIST_OBJECT* aJonction, bool aIsBus, int aIdxStart ); + + + /** + * Function connectBusLabels + * Propagate the net code (and create it, if not yet existing) between + * all bus label member objects connected by they name. + * Search is done in the entire list + */ + void connectBusLabels(); + + /** + * Set the m_FlagOfConnection member of items in list + * depending on the connection type: + * UNCONNECTED, PAD_CONNECT or NOCONNECT_SYMBOL_PRESENT + * The list is expected sorted by order of net code, + * i.e. items having the same net code are grouped + */ + void setUnconnectedFlag(); + + /** + * Function findBestNetNameForEachNet + * fill the .m_NetNameCandidate member of each item of aNetItemBuffer + * with a reference to the "best" NETLIST_OBJECT usable to give a name to the net + * If no suitable object found, .m_NetNameCandidate is filled with 0. + * The "best" NETLIST_OBJECT is a NETLIST_OBJECT that have the type label + * and by priority order: + * the label is global or local + * the label is in the first sheet in a hierarchy (the root sheet has the most priority) + * alphabetic order. + */ + void findBestNetNameForEachNet(); +}; + + +/** + * Function IsBusLabel + * test if \a aLabel has a bus notation. + * + * @param aLabel A wxString object containing the label to test. + * @return true if text is a bus notation format otherwise false is returned. + */ +extern bool IsBusLabel( const wxString& aLabel ); + +#endif // _CLASS_NETLIST_OBJECT_H_ diff --git a/eeschema/class_sch_screen.h b/eeschema/class_sch_screen.h new file mode 100644 index 00000000..67c6451b --- /dev/null +++ b/eeschema/class_sch_screen.h @@ -0,0 +1,599 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file class_sch_screen.h + * @brief Definitions for the Eeschema program SCH_SCREEN class. + */ + +#ifndef CLASS_SCREEN_H +#define CLASS_SCREEN_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../eeschema/general.h> + + +class LIB_PIN; +class SCH_COMPONENT; +class SCH_SHEET_PATH; +class SCH_SHEET_PIN; +class SCH_LINE; +class SCH_TEXT; +class PLOTTER; + + +enum SCH_LINE_TEST_T +{ + ENTIRE_LENGTH_T, + END_POINTS_ONLY_T, + EXCLUDE_END_POINTS_T +}; + + +/// Max number of sheets in a hierarchy project +#define NB_MAX_SHEET 500 + + +class SCH_SCREEN : public BASE_SCREEN, public KIWAY_HOLDER +{ +private: + + wxString m_fileName; ///< File used to load the screen. + + int m_refCount; ///< Number of sheets referencing this screen. + ///< Delete when it goes to zero. + + /// The size of the paper to print or plot on + PAGE_INFO m_paper; // keep with the MVC 'model' if this class gets split + + TITLE_BLOCK m_titles; + + /// Origin of the auxilliary axis, which is used in exports mostly, but not yet in EESCHEMA + wxPoint m_aux_origin; + + DLIST< SCH_ITEM > m_drawList; ///< Object list for the screen. + + int m_modification_sync; ///< inequality with PART_LIBS::GetModificationHash() + ///< will trigger ResolveAll(). + + /** + * Function addConnectedItemsToBlock + * add items connected at \a aPosition to the block pick list. + *

+ * This method tests all connectible unselected items in the screen that are connected to + * \a aPosition and adds them to the block selection pick list. This is used when a block + * drag is being performed to ensure connections to items in the block are not lost. + *

+ * @param aPosition = The connection point to test. + */ + void addConnectedItemsToBlock( const wxPoint& aPosition ); + +public: + + /** + * Constructor + */ + SCH_SCREEN( KIWAY* aKiway ); + + ~SCH_SCREEN(); + + virtual wxString GetClass() const + { + return wxT( "SCH_SCREEN" ); + } + + const PAGE_INFO& GetPageSettings() const { return m_paper; } + void SetPageSettings( const PAGE_INFO& aPageSettings ) { m_paper = aPageSettings; } + + void SetFileName( const wxString& aFileName ) { m_fileName = aFileName; } + + const wxString& GetFileName() const { return m_fileName; } + + const wxPoint& GetAuxOrigin() const { return m_aux_origin; } + void SetAuxOrigin( const wxPoint& aPosition ) { m_aux_origin = aPosition; } + + const TITLE_BLOCK& GetTitleBlock() const { return m_titles; } + //TITLE_BLOCK& GetTitleBlock() const { return (TITLE_BLOCK&) m_titles; } + void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) { m_titles = aTitleBlock; } + + void DecRefCount(); + + void IncRefCount(); + + int GetRefCount() const { return m_refCount; } + + /** + * Function GetDrawItems(). + * @return - A pointer to the first item in the linked list of draw items. + */ + SCH_ITEM* GetDrawItems() const { return m_drawList.begin(); } + + void Append( SCH_ITEM* aItem ) + { + m_drawList.Append( aItem ); + --m_modification_sync; + } + + /** + * Function Append + * adds \a aList of SCH_ITEM objects to the list for draw items for the sheet. + * + * @param aList A reference to a #DLIST containing the #SCH_ITEM to add to the sheet. + */ + void Append( DLIST< SCH_ITEM >& aList ) + { + m_drawList.Append( aList ); + --m_modification_sync; + } + + /** + * Function GetCurItem + * returns the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem(). + * @return SCH_ITEM* - the one selected, or NULL. + */ + SCH_ITEM* GetCurItem() const { return (SCH_ITEM*) BASE_SCREEN::GetCurItem(); } + + /** + * Function SetCurItem + * sets the currently selected object, m_CurrentItem. + * @param aItem Any object derived from SCH_ITEM + */ + void SetCurItem( SCH_ITEM* aItem ) { BASE_SCREEN::SetCurItem( (EDA_ITEM*) aItem ); } + + /** + * Function Clear + * deletes all draw items and clears the project settings. + */ + void Clear(); + + /** + * Free all the items from the schematic associated with the screen. + * + * This does not delete any sub hierarchies. + */ + void FreeDrawList(); + + /** + * Function GetItem + * checks \a aPosition within a distance of \a aAccuracy for items of type \a aFilter. + * @param aPosition Position in drawing units. + * @param aAccuracy The maximum distance within \a Position to check for an item. + * @param aType The type of item to find or #NOT_USED to find any item type. + * @return The item found that meets the search criteria or NULL if none found. + */ + SCH_ITEM* GetItem( const wxPoint& aPosition, int aAccuracy = 0, + KICAD_T aType = NOT_USED ) const; + + void Place( SCH_EDIT_FRAME* frame, wxDC* DC ) { }; + + /** + * Function CheckComponentsToPartsLink + * initializes or reinitializes the weak reference + * to the LIB_PART for each SCH_COMPONENT found in m_drawList. + * It must be called from: + * - Draw function + * - when loading a schematic file + * - before creating a netlist (in case a library is modified) + */ + void CheckComponentsToPartsLinks(); + + /** + * Function Draw + * draws all the items in the screen to \a aCanvas. + * note: this function is useful only for schematic. + * library editor and library viewer do not use a draw list, and therefore + * draws nothing + * @param aCanvas The canvas item to draw on. + * @param aDC The device context to draw on. + * @param aDrawMode The drawing mode. + * @param aColor The drawing color. + */ + void Draw( EDA_DRAW_PANEL* aCanvas, wxDC* aDC, GR_DRAWMODE aDrawMode, + EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + /** + * Function Plot + * plots all the schematic objects to \a aPlotter. + * note: this function is useful only for schematic. + * library editor and library viewer do not use a draw list, and therefore + * plots nothing + * + * @param aPlotter The plotter object to plot to. + */ + void Plot( PLOTTER* aPlotter ); + + /** + * Function Remove + * removes \a aItem from the schematic associated with this screen. + * + * @note The removed item is not deleted. It is only unlinked from the item list. + * @param aItem Item to be removed from schematic. + */ + void Remove( SCH_ITEM* aItem ); + + /** + * Function DeleteItem + * removes \a aItem from the linked list and deletes the object. If \a aItem is + * is a schematic sheet label, it is removed from the screen associated with the + * sheet that contains the label to be deleted. + * @param aItem The schematic object to be deleted from the screen. + */ + void DeleteItem( SCH_ITEM* aItem ); + + bool CheckIfOnDrawList( SCH_ITEM* st ); + + /** + * Function SchematicCleanUp + * performs routine schematic cleaning including breaking wire and buses and + * deleting identical objects superimposed on top of each other. + * + * @param aCanvas The window to draw on. + * @param aDC The device context used for drawing to \a aCanvas. + * @return True if any schematic clean up was performed. + */ + bool SchematicCleanUp( EDA_DRAW_PANEL* aCanvas = NULL, wxDC* aDC = NULL ); + + /** + * Function TestDanglingEnds + * tests all of the connectible objects in the schematic for unused connection points. + * @param aDC - The device context to draw the dangling status indicators. + * @param aCanvas - The window to draw on. + * @return True if any dangling ends were found. + */ + bool TestDanglingEnds( EDA_DRAW_PANEL* aCanvas = NULL, wxDC* aDC = NULL ); + + /** + * Function ExtractWires + * extracts the old wires, junctions and buses. If \a aCreateCopy is true, replace + * extracted items with a copy of the original. Old items are to be put in undo list, + * and the new ones can be modified by clean up safely. If an abort draw segmat command + * is made, the old wires must be put back into #m_drawList, and the copies must be + * deleted. This is because previously stored undo commands can handle pointers on wires + * or buses, and we do not delete wires or buses, we must put them in undo list. + * + * Because cleanup deletes and/or modify bus and wires, it is easier is to put + * all the existing wires in undo list and use a new copy of wires for cleanup. + */ + void ExtractWires( DLIST< SCH_ITEM >& aList, bool aCreateCopy ); + + /** + * Function ReplaceWires + * replaces all of the wires, buses, and junctions in the screen with \a aWireList. + * + * @param aWireList List of wires to replace the existing wires with. + */ + void ReplaceWires( DLIST< SCH_ITEM >& aWireList ); + + /** + * Function MarkConnections + * add all wires and junctions connected to \a aSegment which are not connected any + * component pin to \a aItemList. + * @param aSegment The segment to test for connections. + */ + void MarkConnections( SCH_LINE* aSegment ); + + /** + * Functions GetConnection + * adds all of the wires and junctions to \a aList that make up a connection to the + * object at \a aPosition. + * @param aPosition The position of the first connection object in drawing units. + * @param aList The pick list to add the connect item to. + * @param aFullConnection If true all the objects that make up this connection are + * add to \a aList. Otherwise, only the objects up to the first + * node are added. + * @return The number of items added to \a aList. + */ + int GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList, bool aFullConnection ); + + /** + * Function BreakSegment + * checks every wire and bus for a intersection at \a aPoint and break into two segments + * at \a aPoint if an intersection is found. + * @param aPoint Test this point for an intersection. + * @return True if any wires or buses were broken. + */ + bool BreakSegment( const wxPoint& aPoint ); + + /** + * Function BreakSegmentsOnJunctions + * tests all junctions and bus entries in the schematic for intersections with wires and + * buses and breaks any intersections into multiple segments. + * @return True if any wires or buses were broken. + */ + bool BreakSegmentsOnJunctions(); + + /* full undo redo management : */ + // use BASE_SCREEN::PushCommandToUndoList( PICKED_ITEMS_LIST* aItem ) + // use BASE_SCREEN::PushCommandToRedoList( PICKED_ITEMS_LIST* aItem ) + + /** + * Function ClearUndoORRedoList + * free the undo or redo list from List element + * Wrappers are deleted. + * data pointed by wrappers are deleted if not in use in schematic + * i.e. when they are copy of a schematic item or they are no more in use (DELETED) + * @param aList = the UNDO_REDO_CONTAINER to clear + * @param aItemCount = the count of items to remove. < 0 for all items + * items are removed from the beginning of the list. + * So this function can be called to remove old commands + */ + virtual void ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount = -1 ); + + /** + * Function Save + * writes the data structures for this object out to \a aFile in "*.sch" format. + * + * @param aFile The FILE to write to. + * @return bool - true if success writing else false. + */ + bool Save( FILE* aFile ) const; + + /** + * Clear the state flags of all the items in the screen. + */ + void ClearDrawingState(); + + int CountConnectedItems( const wxPoint& aPos, bool aTestJunctions ) const; + + /** + * Function IsJunctionNeeded + * tests if a junction is required for the items at \a aPosition on the screen. + *

+ * A junction is required at \a aPosition if the following criteria are satisfied: + *

    + *
  • one wire midpoint, one or more wire endpoints and no junction.
  • + *
  • three or more wire endpoints and no junction.
  • + *
  • two wire midpoints and no junction
  • + *
  • one wire midpoint, a component pin, and no junction.
  • + *
  • three wire endpoints, a component pin, and no junction.
  • + *
+ *

+ * @param aPosition The position to test. + * @return True if a junction is required at \a aPosition. + */ + bool IsJunctionNeeded( const wxPoint& aPosition ); + + /** + * Function IsTerminalPoint + * tests if \a aPosition is a connection point on \a aLayer. + * + * @param aPosition Position to test. + * @param aLayer The layer type to test against. Valid layer types are #LAYER_NOTES, + * #LAYER_BUS, and #LAYER_WIRE. + * @return True if \a Position is a connection point on \a aLayer. + */ + bool IsTerminalPoint( const wxPoint& aPosition, int aLayer ); + + /** + * Function GetPin + * test the screen for a component pin item at \a aPosition. + * @param aPosition Position to test. + * @param aComponent The component if a pin was found, otherwise NULL. + * @param aEndPointOnly Set to true to test if \a aPosition is the connection + * point of the pin. + * @return The pin item if found, otherwise NULL. + */ + LIB_PIN* GetPin( const wxPoint& aPosition, SCH_COMPONENT** aComponent = NULL, + bool aEndPointOnly = false ) const; + + /** + * Function GetSheet + * returns a sheet object pointer that is named \a aName. + * + * @note The screen hierarchy is not descened. + * @param aName is the case insensitive name of the sheet. + * @return A pointer to the SCH_SHEET object found or NULL. + */ + SCH_SHEET* GetSheet( const wxString& aName ); + + /** + * Function GetSheetLabel + * test the screen if \a aPosition is a sheet label object. + * @param aPosition The position to test. + * @return The sheet label object if found otherwise NULL. + */ + SCH_SHEET_PIN* GetSheetLabel( const wxPoint& aPosition ); + + /** + * Function ClearAnnotation + * clears the annotation for the components in \a aSheetPath on the screen. + * @param aSheetPath The sheet path of the component annotation to clear. If NULL then + * the entire hierarchy is cleared. + */ + void ClearAnnotation( SCH_SHEET_PATH* aSheetPath ); + + /** + * Function GetHierarchicalItems + * adds all schematic sheet and component object in the screen to \a aItems. + * @param aItems Hierarchical item list to fill. + */ + void GetHierarchicalItems( EDA_ITEMS& aItems ); + + /** + * Function GetNode + * returns all the items at \a aPosition that form a node. + * + * @param aPosition The wxPoint to test for node items. + * @param aList A #EDA_ITEMS container to place the items found. + * @return The number of node items found at \a aPosition. + */ + int GetNode( const wxPoint& aPosition, EDA_ITEMS& aList ); + + /** + * Function GetWireOrBus + * returns a wire or bus item located at \a aPosition. + * + * @param aPosition The wxPoint to test for node items. + * @return The SCH_LINE* of the wire or bus item found at \a aPosition or NULL if item not + * found. + */ + SCH_LINE* GetWireOrBus( const wxPoint& aPosition ); + + /** + * Function GetLine + * returns a line item located at \a aPosition. + * + * @param aPosition The wxPoint to test for a line item. + * @param aAccuracy Amount to inflate the item hit test bounding box. + * @param aLayer The layer the line is drawn upon. + * @param aSearchType Additional line test criteria. + * @return The SCH_LINE* of the wire item found at \a aPosition or NULL if item not + * found. + */ + SCH_LINE* GetLine( const wxPoint& aPosition, int aAccuracy = 0, int aLayer = LAYER_NOTES, + SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T ); + + SCH_LINE* GetWire( const wxPoint& aPosition, int aAccuracy = 0, + SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T ) + { + return GetLine( aPosition, aAccuracy, LAYER_WIRE, aSearchType ); + } + + SCH_LINE* GetBus( const wxPoint& aPosition, int aAccuracy = 0, + SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T ) + { + return GetLine( aPosition, aAccuracy, LAYER_BUS, aSearchType ); + } + + /** + * Function GetLabel + * returns a label item located at \a aPosition. + * + * @param aPosition The wxPoint to test for label items. + * @param aAccuracy Amount to inflate the item hit test bounding box. + * @return The SCH_TEXT* of the label item found at \a aPosition or NULL if item not + * found. + */ + SCH_TEXT* GetLabel( const wxPoint& aPosition, int aAccuracy = 0 ); + + /** + * Function SetFootprintField + * searches screen for a component with \a aReference and set the footprint field to + * \a aFootPrint if found. + * + * @param aSheetPath The sheet path used to look up the reference designator. + * @param aReference The reference designator of the component. + * @param aFootPrint The value to set the footprint field. + * @param aSetVisible The value to set the field visibility flag. + * @return True if \a aReference was found otherwise false. + */ + bool SetComponentFootprint( SCH_SHEET_PATH* aSheetPath, const wxString& aReference, + const wxString& aFootPrint, bool aSetVisible ); + + /** + * Function SelectBlockItems + * creates a list of items found when a block command is initiated. The items selected + * depend on the block command. If the drag block command is issued, than any items + * connected to items in the block are also selected. + */ + void SelectBlockItems(); + + /** + * Function UpdatePickList + * adds all the items in the screen within the block selection rectangle to the pick list. + * @return The number of items in the pick list. + */ + int UpdatePickList(); + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // overload +#endif +}; + + +/** + * Class SCH_SCREENS + * is a container class that holds multiple SCH_SCREENs in a hierarchy. + * Individual SCH_SCREENs are unique, and correspond to .sch files. + */ +class SCH_SCREENS +{ +private: + std::vector< SCH_SCREEN* > m_screens; + unsigned int m_index; + +public: + SCH_SCREENS(); + ~SCH_SCREENS(); + int GetCount() const { return m_screens.size(); } + SCH_SCREEN* GetFirst(); + SCH_SCREEN* GetNext(); + SCH_SCREEN* GetScreen( unsigned int aIndex ) const; + + /** + * Function ClearAnnotation + * clears the annotation for all components in the hierarchy. + */ + void ClearAnnotation(); + + /** + * Function SchematicCleanUp + * merges and breaks wire segments in the entire schematic hierarchy. + */ + void SchematicCleanUp(); + + /** + * Function ReplaceDuplicateTimeStamps + * test all sheet and component objects in the schematic for duplicate time stamps + * an replaces them as necessary. Time stamps must be unique in order for complex + * hierarchies know which components go to which sheets. + * @return The number of duplicate time stamps replaced. + */ + int ReplaceDuplicateTimeStamps(); + + /** + * Function DeleteAllMarkers + * deletes all electronic rules check markers of \a aMarkerType from all the screens in + * the list. + * @param aMarkerType Type of markers to be deleted. + */ + void DeleteAllMarkers( enum MARKER_BASE::TYPEMARKER aMarkerType ); + + /** + * Function GetMarkerCount + * returns the number of ERC markers of \a aMarkerType from all of the screens in the list. + * + * @param aMarkerType Indicates the type of marker to count. if MARKER_UNSPEC + * all markers are counted. + * @param aSeverity Indicates the error level of marker to count. + * useMARKER_SEVERITY_UNSPEC to count all markersof the specified type + * @return int count of the markers found. + */ + int GetMarkerCount( enum MARKER_BASE::TYPEMARKER aMarkerType, + enum MARKER_BASE::MARKER_SEVERITY aSeverity ); + +private: + void AddScreenToList( SCH_SCREEN* aScreen ); + void BuildScreenList( EDA_ITEM* aItem ); +}; + +#endif /* CLASS_SCREEN_H */ diff --git a/eeschema/cmp_library.keywords b/eeschema/cmp_library.keywords new file mode 100644 index 00000000..6640005c --- /dev/null +++ b/eeschema/cmp_library.keywords @@ -0,0 +1,33 @@ +header +version +name +author +comment +license +url +copyright +symbol +component +field +tags +docs +drawing +arc +start +end +rectangle +position +width +height +polyline +circle +center +radius +text +orientation +pin +number +length +electical_type +style +fill_style diff --git a/eeschema/cmp_library_lexer.cpp b/eeschema/cmp_library_lexer.cpp new file mode 100644 index 00000000..750bbaf6 --- /dev/null +++ b/eeschema/cmp_library_lexer.cpp @@ -0,0 +1,6 @@ +/* + * Do not delete this file. It will eventually become the new component + * library file DSN lexer which will replace the current library and library + * document file formats. + */ +#include diff --git a/eeschema/component_references_lister.cpp b/eeschema/component_references_lister.cpp new file mode 100644 index 00000000..6796ef39 --- /dev/null +++ b/eeschema/component_references_lister.cpp @@ -0,0 +1,788 @@ +/** + * @file component_references_lister.cpp + * @brief Code for creating a flat list of components needed for annotation and BOM. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2011 jean-pierre Charras + * Copyright (C) 1992-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 KiCad Developers, see change_log.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 +#include +#include + +#include +#include +#include +#include +#include + +#include + + +//#define USE_OLD_ALGO + + +void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex ) +{ + if( aIndex < componentFlatList.size() ) + componentFlatList.erase( componentFlatList.begin() + aIndex ); +} + + +bool SCH_REFERENCE_LIST::sortByXPosition( const SCH_REFERENCE& item1, + const SCH_REFERENCE& item2 ) +{ + int ii = item1.CompareRef( item2 ); + + if( ii == 0 ) + ii = item1.m_SheetNum - item2.m_SheetNum; + if( ii == 0 ) + ii = item1.m_CmpPos.x - item2.m_CmpPos.x; + if( ii == 0 ) + ii = item1.m_CmpPos.y - item2.m_CmpPos.y; + if( ii == 0 ) + ii = item1.m_TimeStamp - item2.m_TimeStamp; + + return ii < 0; +} + +bool SCH_REFERENCE_LIST::sortByYPosition( const SCH_REFERENCE& item1, + const SCH_REFERENCE& item2 ) +{ + int ii = item1.CompareRef( item2 ); + + if( ii == 0 ) + ii = item1.m_SheetNum - item2.m_SheetNum; + if( ii == 0 ) + ii = item1.m_CmpPos.y - item2.m_CmpPos.y; + if( ii == 0 ) + ii = item1.m_CmpPos.x - item2.m_CmpPos.x; + if( ii == 0 ) + ii = item1.m_TimeStamp - item2.m_TimeStamp; + + return ii < 0; +} + + +bool SCH_REFERENCE_LIST::sortByRefAndValue( const SCH_REFERENCE& item1, + const SCH_REFERENCE& item2 ) +{ + int ii = item1.CompareRef( item2 ); + if( ii == 0 ) + ii = item1.CompareValue( item2 ); + if( ii == 0 ) + ii = item1.m_Unit - item2.m_Unit; + if( ii == 0 ) + ii = item1.m_SheetNum - item2.m_SheetNum; + if( ii == 0 ) + ii = item1.m_CmpPos.x - item2.m_CmpPos.x; + if( ii == 0 ) + ii = item1.m_CmpPos.y - item2.m_CmpPos.y; + if( ii == 0 ) + ii = item1.m_TimeStamp - item2.m_TimeStamp; + + return ii < 0; +} + + +bool SCH_REFERENCE_LIST::sortByReferenceOnly( const SCH_REFERENCE& item1, + const SCH_REFERENCE& item2 ) +{ + int ii; + + ii = RefDesStringCompare( item1.GetRef(), item2.GetRef() ); + + if( ii == 0 ) + { + ii = item1.m_RootCmp->GetField( VALUE )->GetText().CmpNoCase( item2.m_RootCmp->GetField( VALUE )->GetText() ); + } + + if( ii == 0 ) + { + ii = item1.m_Unit - item2.m_Unit; + } + + return ii < 0; +} + + +bool SCH_REFERENCE_LIST::sortByTimeStamp( const SCH_REFERENCE& item1, + const SCH_REFERENCE& item2 ) +{ + int ii = item1.m_SheetPath.Cmp( item2.m_SheetPath ); + + if( ii == 0 ) + ii = item1.m_TimeStamp - item2.m_TimeStamp; + + return ii < 0; +} + +int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit ) +{ + int NumRef; + + NumRef = componentFlatList[aIndex].m_NumRef; + + for( size_t ii = 0; ii < componentFlatList.size(); ii++ ) + { + if( ( aIndex == ii ) + || ( componentFlatList[ii].m_IsNew ) + || ( componentFlatList[ii].m_NumRef != NumRef ) + || ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) != 0 ) ) + continue; + + if( componentFlatList[ii].m_Unit == aUnit ) + return (int) ii; + } + + return -1; +} + + +void SCH_REFERENCE_LIST::RemoveSubComponentsFromList() +{ + SCH_COMPONENT* libItem; + wxString oldName; + wxString currName; + + // The component list **MUST** be sorted by reference and by unit number + // in order to find all parts of a component + SortByReferenceOnly(); + + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + + libItem = componentFlatList[ii].m_RootCmp; + if( libItem == NULL ) + continue; + + currName = componentFlatList[ii].GetRef(); + + if( !oldName.IsEmpty() ) + { + if( oldName == currName ) // currName is a subpart of oldName: remove it + { + componentFlatList.erase( componentFlatList.begin() + ii ); + ii--; + } + } + + oldName = currName; + } +} + + +void SCH_REFERENCE_LIST::ResetHiddenReferences() +{ + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + if( componentFlatList[ii].GetRefStr()[0] == '#' ) + { + componentFlatList[ii].m_IsNew = true; + componentFlatList[ii].m_NumRef = 0; + } + } +} + + +void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId ) +{ + aIdList.clear(); + + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + if( ( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) == 0 ) + && ( componentFlatList[ii].m_NumRef >= aMinRefId ) ) + aIdList.push_back( componentFlatList[ii].m_NumRef ); + } + + sort( aIdList.begin(), aIdList.end() ); + + // Ensure each reference number appears only once. If there are components with + // multiple parts per package the same number will be stored for each part. + std::vector< int >::iterator it = unique( aIdList.begin(), aIdList.end() ); + + // Using the C++ unique algorithm only moves the duplicate entries to the end of + // of the array. This removes the duplicate entries from the array. + aIdList.resize( it - aIdList.begin() ); +} + + +int SCH_REFERENCE_LIST::GetLastReference( int aIndex, int aMinValue ) +{ + int lastNumber = aMinValue; + + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + // search only for the current reference prefix: + if( componentFlatList[aIndex].CompareRef( componentFlatList[ii] ) != 0 ) + continue; + + // update max value for the current reference prefix + if( lastNumber < componentFlatList[ii].m_NumRef ) + lastNumber = componentFlatList[ii].m_NumRef; + } + + return lastNumber; +} + + +int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ) +{ + int expectedId = aFirstValue; + + // We search for expected Id a value >= aFirstValue. + // Skip existing Id < aFirstValue + unsigned ii = 0; + + for( ; ii < aIdList.size(); ii++ ) + { + if( expectedId <= aIdList[ii] ) + break; + } + + // Ids are sorted by increasing value, from aFirstValue + // So we search from aFirstValue the first not used value, i.e. the first hole in list. + for( ; ii < aIdList.size(); ii++ ) + { + if( expectedId != aIdList[ii] ) // This id is not yet used. + { + // Insert this free Id, in order to keep list sorted + aIdList.insert( aIdList.begin() + ii, expectedId ); + return expectedId; + } + + expectedId++; + } + + // All existing Id are tested, and all values are found in use. + // So Create a new one. + aIdList.push_back( expectedId ); + return expectedId; +} + + +void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, + SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap ) +{ + if ( componentFlatList.size() == 0 ) + return; + + int LastReferenceNumber = 0; + int NumberOfUnits, Unit; + + // Components with an invisible reference (power...) always are re-annotated. + ResetHiddenReferences(); + + /* calculate index of the first component with the same reference prefix + * than the current component. All components having the same reference + * prefix will receive a reference number with consecutive values: + * IC .. will be set to IC4, IC4, IC5 ... + */ + unsigned first = 0; + + // calculate the last used number for this reference prefix: +#ifdef USE_OLD_ALGO + int minRefId = 0; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId; + + LastReferenceNumber = GetLastReference( first, minRefId ); +#else + int minRefId = 1; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[first].m_SheetNum * aSheetIntervalId + 1; + + // This is the list of all Id already in use for a given reference prefix. + // Will be refilled for each new reference prefix. + std::vectoridList; + GetRefsInUse( first, idList, minRefId ); +#endif + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + if( componentFlatList[ii].m_Flag ) + continue; + + // Check whether this component is in aLockedUnitMap. + SCH_REFERENCE_LIST* lockedList = NULL; + BOOST_FOREACH( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair, aLockedUnitMap ) + { + unsigned n_refs = pair.second.GetCount(); + for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI ) + { + SCH_REFERENCE &thisRef = pair.second[thisRefI]; + + if( thisRef.IsSameInstance( componentFlatList[ii] ) ) + { + lockedList = &pair.second; + break; + } + } + if( lockedList != NULL ) break; + } + + if( ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 ) + || ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) ) ) + { + // New reference found: we need a new ref number for this reference + first = ii; +#ifdef USE_OLD_ALGO + minRefId = 0; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId; + + LastReferenceNumber = componentFlatList.GetLastReference( ii, minRefId ); +#else + minRefId = 1; + + // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId + if( aUseSheetNum ) + minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId + 1; + + GetRefsInUse( first, idList, minRefId ); +#endif + } + + // Annotation of one part per package components (trivial case). + if( componentFlatList[ii].GetLibComponent()->GetUnitCount() <= 1 ) + { + if( componentFlatList[ii].m_IsNew ) + { +#ifdef USE_OLD_ALGO + LastReferenceNumber++; +#else + LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); +#endif + componentFlatList[ii].m_NumRef = LastReferenceNumber; + } + + componentFlatList[ii].m_Unit = 1; + componentFlatList[ii].m_Flag = 1; + componentFlatList[ii].m_IsNew = false; + continue; + } + + // Annotation of multi-unit parts ( n units per part ) (complex case) + NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetUnitCount(); + + if( componentFlatList[ii].m_IsNew ) + { +#ifdef USE_OLD_ALGO + LastReferenceNumber++; +#else + LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); +#endif + componentFlatList[ii].m_NumRef = LastReferenceNumber; + + if( !componentFlatList[ii].IsUnitsLocked() ) + componentFlatList[ii].m_Unit = 1; + + componentFlatList[ii].m_Flag = 1; + } + + // If this component is in aLockedUnitMap, copy the annotation to all + // components that are not it + if( lockedList != NULL ) + { + unsigned n_refs = lockedList->GetCount(); + for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI ) + { + SCH_REFERENCE &thisRef = (*lockedList)[thisRefI]; + if( thisRef.IsSameInstance( componentFlatList[ii] ) ) + { + // This is the component we're currently annotating. Hold the unit! + componentFlatList[ii].m_Unit = thisRef.m_Unit; + } + + if( thisRef.CompareValue( componentFlatList[ii] ) != 0 ) continue; + if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 ) continue; + + // Find the matching component + for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ ) + { + if( ! thisRef.IsSameInstance( componentFlatList[jj] ) ) continue; + componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef; + componentFlatList[jj].m_Unit = thisRef.m_Unit; + componentFlatList[jj].m_IsNew = false; + componentFlatList[jj].m_Flag = 1; + break; + } + } + } + + else + { + /* search for others units of this component. + * we search for others parts that have the same value and the same + * reference prefix (ref without ref number) + */ + for( Unit = 1; Unit <= NumberOfUnits; Unit++ ) + { + if( componentFlatList[ii].m_Unit == Unit ) + continue; + + int found = FindUnit( ii, Unit ); + + if( found >= 0 ) + continue; // this unit exists for this reference (unit already annotated) + + // Search a component to annotate ( same prefix, same value, not annotated) + for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ ) + { + if( componentFlatList[jj].m_Flag ) // already tested + continue; + + if( componentFlatList[ii].CompareRef( componentFlatList[jj] ) != 0 ) + continue; + + if( componentFlatList[jj].CompareValue( componentFlatList[ii] ) != 0 ) + continue; + + if( componentFlatList[jj].CompareLibName( componentFlatList[ii] ) != 0 ) + continue; + + if( !componentFlatList[jj].m_IsNew ) + continue; + + // Component without reference number found, annotate it if possible + if( !componentFlatList[jj].IsUnitsLocked() + || ( componentFlatList[jj].m_Unit == Unit ) ) + { + componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef; + componentFlatList[jj].m_Unit = Unit; + componentFlatList[jj].m_Flag = 1; + componentFlatList[jj].m_IsNew = false; + break; + } + } + } + } + } +} + + +int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList ) +{ + int error = 0; + wxString tmp; + wxString msg; + + SortByRefAndValue(); + + // Spiit reference designators into name (prefix) and number: IC1 becomes IC, and 1. + SplitReferences(); + + // count not yet annotated items or annotation error. + for( unsigned ii = 0; ii < componentFlatList.size(); ii++ ) + { + msg.Empty(); + tmp.Empty(); + + if( componentFlatList[ii].m_IsNew ) // Not yet annotated + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + msg.Printf( _( "Item not annotated: %s%s (unit %d)\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ), + componentFlatList[ii].m_Unit ); + } + else + { + msg.Printf( _( "Item not annotated: %s%s\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ) ); + } + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" ) ); + + error++; + break; + } + + // Error if unit number selected does not exist ( greater than the number of + // parts in the component ). This can happen if a component has changed in a + // library after a previous annotation. + if( std::max( componentFlatList[ii].GetLibComponent()->GetUnitCount(), 1 ) + < componentFlatList[ii].m_Unit ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + msg.Printf( _( "Error item %s%s unit %d and no more than %d parts\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ), + componentFlatList[ii].m_Unit, + componentFlatList[ii].GetLibComponent()->GetUnitCount() ); + + if( aMessageList ) + aMessageList->Add( msg ); + + error++; + break; + } + } + + if( error ) + return error; + + // count the duplicated elements (if all are annotated) + int imax = componentFlatList.size() - 1; + + for( int ii = 0; (ii < imax) && (error < 4); ii++ ) + { + msg.Empty(); + tmp.Empty(); + + if( ( componentFlatList[ii].CompareRef( componentFlatList[ii + 1] ) != 0 ) + || ( componentFlatList[ii].m_NumRef != componentFlatList[ii + 1].m_NumRef ) ) + continue; + + // Same reference found. If same unit, error! + if( componentFlatList[ii].m_Unit == componentFlatList[ii + 1].m_Unit ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + msg.Printf( _( "Multiple item %s%s (unit %d)\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ), + componentFlatList[ii].m_Unit ); + } + else + { + msg.Printf( _( "Multiple item %s%s\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ) ); + } + + if( aMessageList ) + aMessageList->Add( msg ); + + error++; + continue; + } + + /* Test error if units are different but number of parts per package + * too high (ex U3 ( 1 part) and we find U3B this is an error) */ + if( componentFlatList[ii].GetLibComponent()->GetUnitCount() + != componentFlatList[ii + 1].GetLibComponent()->GetUnitCount() ) + { + if( componentFlatList[ii].m_NumRef >= 0 ) + tmp << componentFlatList[ii].m_NumRef; + else + tmp = wxT( "?" ); + + if( ( componentFlatList[ii].m_Unit > 0 ) + && ( componentFlatList[ii].m_Unit < 0x7FFFFFFF ) ) + { + msg.Printf( _( "Multiple item %s%s (unit %d)\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ), + componentFlatList[ii].m_Unit ); + } + else + { + msg.Printf( _( "Multiple item %s%s\n" ), + GetChars( componentFlatList[ii].GetRef() ), + GetChars( tmp ) ); + } + + if( aMessageList ) + aMessageList->Add( msg ); + + error++; + } + + // Error if values are different between units, for the same reference + int next = ii + 1; + + if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 ) + { + msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ), + GetChars( componentFlatList[ii].GetRef() ), + componentFlatList[ii].m_NumRef, + GetChars( LIB_PART::SubReference( + componentFlatList[ii].m_Unit ) ), + GetChars( componentFlatList[ii].m_Value->GetText() ), + GetChars( componentFlatList[next].GetRef() ), + componentFlatList[next].m_NumRef, + GetChars( LIB_PART::SubReference( + componentFlatList[next].m_Unit ) ), + GetChars( componentFlatList[next].m_Value->GetText() ) ); + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" )); + + error++; + } + } + + // count the duplicated time stamps + SortByTimeStamp(); + + for( int ii = 0; ( ii < imax ) && ( error < 4 ); ii++ ) + { + if( ( componentFlatList[ii].m_TimeStamp != componentFlatList[ii + 1].m_TimeStamp ) + || ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) ) + continue; + + // Same time stamp found. + wxString full_path; + + full_path.Printf( wxT( "%s%8.8X" ), + GetChars( componentFlatList[ii].GetSheetPath().Path() ), + componentFlatList[ii].m_TimeStamp ); + + msg.Printf( _( "Duplicate time stamp (%s) for %s%d and %s%d" ), + GetChars( full_path ), + GetChars( componentFlatList[ii].GetRef() ), componentFlatList[ii].m_NumRef, + GetChars( componentFlatList[ii + 1].GetRef() ), + componentFlatList[ii + 1].m_NumRef ); + + if( aMessageList ) + aMessageList->Add( msg + wxT( "\n" )); + + error++; + } + + return error; +} + + +SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibComponent, + SCH_SHEET_PATH& aSheetPath ) +{ + wxASSERT( aComponent != NULL && aLibComponent != NULL ); + + m_RootCmp = aComponent; + m_Entry = aLibComponent; + m_Unit = aComponent->GetUnitSelection( &aSheetPath ); + m_SheetPath = aSheetPath; + m_IsNew = false; + m_Flag = 0; + m_TimeStamp = aComponent->GetTimeStamp(); + m_CmpPos = aComponent->GetPosition(); + m_SheetNum = 0; + + if( aComponent->GetRef( &aSheetPath ).IsEmpty() ) + aComponent->SetRef( &aSheetPath, wxT( "DefRef?" ) ); + + SetRef( aComponent->GetRef( &aSheetPath ) ); + + m_NumRef = -1; + + if( aComponent->GetField( VALUE )->GetText().IsEmpty() ) + aComponent->GetField( VALUE )->SetText( wxT( "~" ) ); + + m_Value = aComponent->GetField( VALUE ); +} + + +void SCH_REFERENCE::Annotate() +{ + if( m_NumRef < 0 ) + m_Ref += wxChar( '?' ); + else + m_Ref = TO_UTF8( GetRef() << m_NumRef ); + + m_RootCmp->SetRef( &m_SheetPath, FROM_UTF8( m_Ref.c_str() ) ); + m_RootCmp->SetUnit( m_Unit ); + m_RootCmp->SetUnitSelection( &m_SheetPath, m_Unit ); +} + + +void SCH_REFERENCE::Split() +{ + std::string refText = GetRefStr(); + + m_NumRef = -1; + + int ll = refText.length() - 1; + + if( refText[ll] == '?' ) + { + m_IsNew = true; + + if( !IsUnitsLocked() ) + m_Unit = 0x7FFFFFFF; + + refText.erase( ll ); // delete last char + + SetRefStr( refText ); + } + else if( isdigit( refText[ll] ) == 0 ) + { + m_IsNew = true; + + if( !IsUnitsLocked() ) + m_Unit = 0x7FFFFFFF; + } + else + { + while( ll >= 0 ) + { + if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) ) + ll--; + else + { + if( isdigit( refText[ll + 1] ) ) + { + // null terminated C string into cp + const char* cp = refText.c_str() + ll + 1; + + m_NumRef = atoi( cp ); + } + + refText.erase( ll+1 ); // delete from ll+1 to end + break; + } + } + + SetRefStr( refText ); + } +} diff --git a/eeschema/component_tree_search_container.cpp b/eeschema/component_tree_search_container.cpp new file mode 100644 index 00000000..c3061f95 --- /dev/null +++ b/eeschema/component_tree_search_container.cpp @@ -0,0 +1,443 @@ +/* -*- c++ -*- + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Henner Zeller + * Copyright (C) 2015 KiCad Developers, see change_log.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 + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +// Each node gets this lowest score initially, without any matches applied. Matches +// will then increase this score depending on match quality. +// This way, an empty search string will result in all components being displayed as they +// have the minimum score. However, in that case, we avoid expanding all the nodes asd the +// result is very unspecific. +static const unsigned kLowestDefaultScore = 1; + +struct COMPONENT_TREE_SEARCH_CONTAINER::TREE_NODE +{ + // Levels of nodes. + enum NODE_TYPE { + TYPE_LIB, + TYPE_ALIAS, + TYPE_UNIT + }; + + TREE_NODE(NODE_TYPE aType, TREE_NODE* aParent, LIB_ALIAS* aAlias, + const wxString& aName, const wxString& aDisplayInfo, + const wxString& aSearchText ) + : Type( aType ), + Parent( aParent ), Alias( aAlias ), Unit( 0 ), + DisplayName( aName ), + DisplayInfo( aDisplayInfo ), + MatchName( aName.Lower() ), + SearchText( aSearchText.Lower() ), + MatchScore( 0 ), PreviousScore( 0 ) + { + } + + const NODE_TYPE Type; ///< Type of node in the hierarchy. + TREE_NODE* const Parent; ///< NULL if library, pointer to parent when component/alias. + LIB_ALIAS* const Alias; ///< Component alias associated with this entry. + int Unit; ///< Part number; Assigned: >= 1; default = 0 + const wxString DisplayName; ///< Exact name as displayed to the user. + const wxString DisplayInfo; ///< Additional info displayed in the tree (description..) + + const wxString MatchName; ///< Preprocessed: lowercased display name. + const wxString SearchText; ///< Other text (keywords, description..) to search in. + + unsigned MatchScore; ///< Result-Score after UpdateSearchTerm() + unsigned PreviousScore; ///< Optimization: used to see if we need any tree update. + wxTreeItemId TreeId; ///< Tree-ID if stored in the tree (if MatchScore > 0). +}; + + +// Sort tree nodes by reverse match-score (bigger is first), then alphabetically. +// Library (i.e. the ones that don't have a parent) are always sorted before any +// leaf nodes. Component +bool COMPONENT_TREE_SEARCH_CONTAINER::scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 ) +{ + if( a1->Type != a2->Type ) + return a1->Type < a2->Type; + + if( a1->MatchScore != a2->MatchScore ) + return a1->MatchScore > a2->MatchScore; // biggest first. + + if( a1->Parent != a2->Parent ) + return scoreComparator( a1->Parent, a2->Parent ); + + return a1->MatchName.Cmp( a2->MatchName ) < 0; +} + + +COMPONENT_TREE_SEARCH_CONTAINER::COMPONENT_TREE_SEARCH_CONTAINER( PART_LIBS* aLibs ) + : m_tree( NULL ), + m_libraries_added( 0 ), + m_components_added( 0 ), + m_preselect_unit_number( -1 ), + m_libs( aLibs ), + m_filter( CMP_FILTER_NONE ) +{ +} + + +COMPONENT_TREE_SEARCH_CONTAINER::~COMPONENT_TREE_SEARCH_CONTAINER() +{ + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + delete node; + m_nodes.clear(); +} + + +void COMPONENT_TREE_SEARCH_CONTAINER::SetPreselectNode( const wxString& aComponentName, + int aUnit ) +{ + m_preselect_node_name = aComponentName.Lower(); + m_preselect_unit_number = aUnit; +} + + +void COMPONENT_TREE_SEARCH_CONTAINER::SetTree( wxTreeCtrl* aTree ) +{ + m_tree = aTree; + UpdateSearchTerm( wxEmptyString ); +} + + +void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( PART_LIB& aLib ) +{ + wxArrayString all_aliases; + + if( m_filter == CMP_FILTER_POWER ) + aLib.GetEntryTypePowerNames( all_aliases ); + else + aLib.GetEntryNames( all_aliases ); + + AddAliasList( aLib.GetName(), all_aliases, &aLib ); + + ++m_libraries_added; +} + + +void COMPONENT_TREE_SEARCH_CONTAINER::AddAliasList( const wxString& aNodeName, + const wxArrayString& aAliasNameList, + PART_LIB* aOptionalLib ) +{ + TREE_NODE* const lib_node = new TREE_NODE( TREE_NODE::TYPE_LIB, NULL, NULL, + aNodeName, wxEmptyString, wxEmptyString ); + m_nodes.push_back( lib_node ); + + BOOST_FOREACH( const wxString& aName, aAliasNameList ) + { + LIB_ALIAS* a; + + if( aOptionalLib ) + a = aOptionalLib->FindAlias( aName ); + else + a = m_libs->FindLibraryEntry( aName, wxEmptyString ); + + if( a == NULL ) + continue; + + wxString search_text; + search_text = ( a->GetKeyWords().empty() ) ? wxT(" ") : a->GetKeyWords(); + search_text += a->GetDescription(); + + wxString display_info; + + if( !a->GetDescription().empty() ) + { + // Preformatting. Unfortunately, the tree widget doesn't have columns + // and using tabs does not work very well or does not work at all + // (depending on OS versions). So indent with spaces in fixed-font width. + + // The 98%-ile of length of strings found in the standard library is 15 + // characters. Use this as a reasonable cut-off point for aligned indentation. + // For the few component names longer than that, the description is indented a + // bit more. + // The max found in the default lib would be 20 characters, but that creates too + // much visible whitespace for the less extreme component names. + const int COLUMN_DESCR_POS = 15; + const int indent_len = COLUMN_DESCR_POS - a->GetName().length(); + display_info = wxString::Format( wxT( " %*s [ %s ]" ), + indent_len > 0 ? indent_len : 0, wxT( "" ), + GetChars( a->GetDescription() ) ); + } + + TREE_NODE* alias_node = new TREE_NODE( TREE_NODE::TYPE_ALIAS, lib_node, + a, a->GetName(), display_info, search_text ); + m_nodes.push_back( alias_node ); + + if( a->GetPart()->IsMulti() ) // Add all units as sub-nodes. + { + for( int u = 1; u <= a->GetPart()->GetUnitCount(); ++u ) + { + wxString unitName = _("Unit"); + unitName += wxT( " " ) + LIB_PART::SubReference( u, false ); + TREE_NODE* unit_node = new TREE_NODE( TREE_NODE::TYPE_UNIT, + alias_node, a, + unitName, + wxEmptyString, wxEmptyString ); + unit_node->Unit = u; + m_nodes.push_back( unit_node ); + } + } + + ++m_components_added; + } +} + + +LIB_ALIAS* COMPONENT_TREE_SEARCH_CONTAINER::GetSelectedAlias( int* aUnit ) +{ + if( m_tree == NULL ) + return NULL; + + const wxTreeItemId& select_id = m_tree->GetSelection(); + + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + { + if( node->MatchScore > 0 && node->TreeId == select_id ) { + if( aUnit && node->Unit > 0 ) + *aUnit = node->Unit; + return node->Alias; + } + } + return NULL; +} + + +// Creates a score depending on the position of a string match. If the position +// is 0 (= prefix match), this returns the maximum score. This degrades until +// pos == max, which returns a score of 0; +// Evertyhing else beyond that is just 0. Only values >= 0 allowed for position and max. +// +// @param aPosition is the position a string has been found in a substring. +// @param aMaximum is the maximum score this function returns. +// @return position dependent score. +static int matchPosScore(int aPosition, int aMaximum) +{ + return ( aPosition < aMaximum ) ? aMaximum - aPosition : 0; +} + + +void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch ) +{ + if( m_tree == NULL ) + return; +//#define SHOW_CALC_TIME // uncomment this to show calculation time + +#ifdef SHOW_CALC_TIME + unsigned starttime = GetRunningMicroSecs(); +#endif + + // We score the list by going through it several time, essentially with a complexity + // of O(n). For the default library of 2000+ items, this typically takes less than 5ms + // on an i5. Good enough, no index needed. + + // Initial AND condition: Leaf nodes are considered to match initially. + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + { + node->PreviousScore = node->MatchScore; + node->MatchScore = ( node->Type == TREE_NODE::TYPE_LIB ) ? 0 : kLowestDefaultScore; + } + + // Create match scores for each node for all the terms, that come space-separated. + // Scoring adds up values for each term according to importance of the match. If a term does + // not match at all, the result is thrown out of the results (AND semantics). + // From high to low + // - Exact match for a ccmponent name gives the highest score, trumping all. + // - A positional score depending of where a term is found as substring; prefix-match: high. + // - substring-match in library name. + // - substring match in keywords and descriptions with positional score. Keywords come + // first so contribute more to the score. + // + // This is of course subject to tweaking. + wxStringTokenizer tokenizer( aSearch ); + + while ( tokenizer.HasMoreTokens() ) + { + const wxString term = tokenizer.GetNextToken().Lower(); + + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + { + if( node->Type != TREE_NODE::TYPE_ALIAS ) + continue; // Only aliases are actually scored here. + + if( node->MatchScore == 0) + continue; // Leaf node without score are out of the game. + + // Keywords and description we only count if the match string is at + // least two characters long. That avoids spurious, low quality + // matches. Most abbreviations are at three characters long. + int found_pos; + + if( term == node->MatchName ) + node->MatchScore += 1000; // exact match. High score :) + else if( (found_pos = node->MatchName.Find( term ) ) != wxNOT_FOUND ) + { + // Substring match. The earlier in the string the better. score += 20..40 + node->MatchScore += matchPosScore( found_pos, 20 ) + 20; + } + else if( node->Parent->MatchName.Find( term ) != wxNOT_FOUND ) + node->MatchScore += 19; // parent name matches. score += 19 + else if( ( found_pos = node->SearchText.Find( term ) ) != wxNOT_FOUND ) + { + // If we have a very short search term (like one or two letters), we don't want + // to accumulate scores if they just happen to be in keywords or description as + // almost any one or two-letter combination shows up in there. + // For longer terms, we add scores 1..18 for positional match (higher in the + // front, where the keywords are). score += 0..18 + node->MatchScore += ( ( term.length() >= 2 ) + ? matchPosScore( found_pos, 17 ) + 1 + : 0 ); + } + else + node->MatchScore = 0; // No match. That's it for this item. + } + } + + // Library nodes have the maximum score seen in any of their children. + // Alias nodes have the score of their parents. + unsigned highest_score_seen = 0; + bool any_change = false; + + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + { + switch( node->Type ) + { + case TREE_NODE::TYPE_ALIAS: + { + any_change |= (node->PreviousScore != node->MatchScore); + // Update library score. + node->Parent->MatchScore = std::max( node->Parent->MatchScore, node->MatchScore ); + highest_score_seen = std::max( highest_score_seen, node->MatchScore ); + } + break; + + case TREE_NODE::TYPE_UNIT: + node->MatchScore = node->Parent->MatchScore; + break; + + default: + break; + } + } + + // The tree update might be slow, so we want to bail out if there is no change. + if( !any_change ) + return; + + // Now: sort all items according to match score, libraries first. + std::sort( m_nodes.begin(), m_nodes.end(), scoreComparator ); + +#ifdef SHOW_CALC_TIME + unsigned sorttime = GetRunningMicroSecs(); +#endif + + // Fill the tree with all items that have a match. Re-arranging, adding and removing changed + // items is pretty complex, so we just re-build the whole tree. + m_tree->Freeze(); + m_tree->DeleteAllItems(); + const wxTreeItemId root_id = m_tree->AddRoot( wxEmptyString ); + const TREE_NODE* first_match = NULL; + const TREE_NODE* preselected_node = NULL; + + BOOST_FOREACH( TREE_NODE* node, m_nodes ) + { + if( node->MatchScore == 0 ) + continue; + + // If we have nodes that go beyond the default score, suppress nodes that + // have the default score. That can happen if they have an honary += 0 score due to + // some one-letter match in the keyword or description. In this case, we prefer matches + // that just have higher scores. Improves relevancy and performance as the tree has to + // display less items. + if( highest_score_seen > kLowestDefaultScore && node->MatchScore == kLowestDefaultScore ) + continue; + + wxString node_text; +#if 0 + // Node text with scoring information for debugging + node_text.Printf( wxT("%s (s=%u)%s"), GetChars(node->DisplayName), + node->MatchScore, GetChars( node->DisplayInfo )); +#else + node_text = node->DisplayName + node->DisplayInfo; +#endif + node->TreeId = m_tree->AppendItem( node->Parent ? node->Parent->TreeId : root_id, + node_text ); + + // If we are a nicely scored alias, we want to have it visible. Also, if there + // is only a single library in this container, we want to have it unfolded + // (example: power library). + if( node->Type == TREE_NODE::TYPE_ALIAS + && ( node->MatchScore > kLowestDefaultScore || m_libraries_added == 1 ) ) + { + m_tree->Expand( node->TreeId ); + + if( first_match == NULL ) + first_match = node; // First, highest scoring: the "I am feeling lucky" element. + } + + // The first node that matches our pre-select criteria is choosen. 'First node' + // means, it shows up in the history, as the history node is displayed very first + // (by virtue of alphabetical ordering) + if( preselected_node == NULL + && node->Type == TREE_NODE::TYPE_ALIAS + && node->MatchName == m_preselect_node_name ) + preselected_node = node; + + // Refinement in case we come accross a matching unit node. + if( preselected_node != NULL && preselected_node->Type == TREE_NODE::TYPE_ALIAS + && node->Parent == preselected_node + && m_preselect_unit_number >= 1 && node->Unit == m_preselect_unit_number ) + preselected_node = node; + } + + if( first_match ) // Highest score search match pre-selected. + { + m_tree->SelectItem( first_match->TreeId ); + m_tree->EnsureVisible( first_match->TreeId ); + } + else if( preselected_node ) // No search, so history item preselected. + { + m_tree->SelectItem( preselected_node->TreeId ); + m_tree->EnsureVisible( preselected_node->TreeId ); + } + + m_tree->Thaw(); + +#ifdef SHOW_CALC_TIME + unsigned endtime = GetRunningMicroSecs(); + wxLogMessage( wxT("sort components %.1f ms, rebuild tree %.1f ms"), + double(sorttime-starttime)/1000.0, double(endtime-sorttime)/1000.0 ); +#endif +} diff --git a/eeschema/component_tree_search_container.h b/eeschema/component_tree_search_container.h new file mode 100644 index 00000000..9d75f918 --- /dev/null +++ b/eeschema/component_tree_search_container.h @@ -0,0 +1,145 @@ +/* -*- c++ -*- + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Henner Zeller + * Copyright (C) 2015 KiCad Developers, see change_log.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 COMPONENT_TREE_SEARCH_CONTAINER_H +#define COMPONENT_TREE_SEARCH_CONTAINER_H + +#include +#include + +class LIB_ALIAS; +class PART_LIB; +class PART_LIBS; +class wxTreeCtrl; +class wxArrayString; + +// class COMPONENT_TREE_SEARCH_CONTAINER +// A container for components that allows to search them matching their name, keywords +// and descriptions, updating a wxTreeCtrl with the results (toplevel nodes: +// libraries, leafs: components), scored by relevance. +// +// The scored result list is adpated on each update on the search-term: this allows +// to have a search-as-you-type experience. +class COMPONENT_TREE_SEARCH_CONTAINER +{ +public: + /** This enum allows a selective filtering of component to list + * currently: no filtering + * list power components only + */ + enum CMP_FILTER_TYPE + { + CMP_FILTER_NONE, ///< no filtering + CMP_FILTER_POWER ///< list components flagged PWR + }; + +public: + COMPONENT_TREE_SEARCH_CONTAINER( PART_LIBS* aLibs ); + ~COMPONENT_TREE_SEARCH_CONTAINER(); + + void SetFilter( CMP_FILTER_TYPE aFilter ) + { + m_filter = aFilter; + } + + /** Function AddLibrary + * Add all the components and their aliases of this library to be searched. + * To be called in the setup phase to fill this container. + * + * @param aLib containting all the components to be added. + */ + void AddLibrary( PART_LIB& aLib ); + + /** Function AddComponentList + * Add the given list of components, given by name, to be searched. + * To be called in the setup phase to fill this container. + * + * @param aNodeName The parent node name the components will show up as leaf. + * @param aAliasNameList List of alias names. + * @param aOptionalLib Library to look up the component names (if NULL: global lookup) + */ + void AddAliasList( const wxString& aNodeName, const wxArrayString& aAliasNameList, + PART_LIB* aOptionalLib ); + + /** Function SetPreselectNode + * Set the component name to be selected in absence of any search-result. + * + * @param aComponentName the component name to be selected. + * @param aUnit the component unit to be selected (if > 0). + */ + void SetPreselectNode( const wxString& aComponentName, int aUnit ); + + /** Function SetTree + * Set the tree to be manipulated. + * Each update of the search term will update the tree, with the most + * scoring component at the top and selected. If a preselect node is set, this + * is displayed. Does not take ownership of the tree. + * + * @param aTree that is to be modified on search updates. + */ + void SetTree( wxTreeCtrl* aTree ); + + /** Function UpdateSearchTerm + * Update the search string provided by the user and narrow down the result list. + * + * This string is a space-separated list of terms, each of which + * is applied to the components list to narrow it down. Results are scored by + * relevancy (e.g. exact match scores higher than prefix-match which in turn scores + * higher than substring match). This updates the search and tree on each call. + * + * @param aSearch is the user-provided search string. + */ + void UpdateSearchTerm( const wxString& aSearch ); + + /** Function GetSelectedAlias + * + * @param aUnit : if not NULL, the selected sub-unit is set here. + * @return the selected alias or NULL if there is none, or there is no tree. + */ + LIB_ALIAS* GetSelectedAlias( int* aUnit ); + + /** + * Function GetComponentsCount + * @return the number of components loaded in the tree + */ + int GetComponentsCount() { return m_components_added; } + + +private: + struct TREE_NODE; + static bool scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 ); + + std::vector m_nodes; + wxTreeCtrl* m_tree; + int m_libraries_added; + int m_components_added; + + wxString m_preselect_node_name; + int m_preselect_unit_number; + + PART_LIBS* m_libs; // no ownership + + enum CMP_FILTER_TYPE m_filter; // the current filter +}; + +#endif /* COMPONENT_TREE_SEARCH_CONTAINER_H */ diff --git a/eeschema/controle.cpp b/eeschema/controle.cpp new file mode 100644 index 00000000..cfd7c6e8 --- /dev/null +++ b/eeschema/controle.cpp @@ -0,0 +1,326 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * eeschema/controle.cpp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, const KICAD_T aFilterList[], + int aHotKeyCommandId ) +{ + SCH_ITEM* item; + LIB_PIN* Pin = NULL; + SCH_COMPONENT* LibItem = NULL; + wxPoint gridPosition = GetNearestGridPosition( aPosition ); + + // Check the on grid position first. There is more likely to be multiple items on + // grid than off grid. + item = LocateItem( gridPosition, aFilterList, aHotKeyCommandId ); + + // If the user aborted the clarification context menu, don't show it again at the + // off grid position. + if( !item && m_canvas->GetAbortRequest() ) + { + m_canvas->SetAbortRequest( false ); + return NULL; + } + + if( !item && (aPosition != gridPosition) ) + item = LocateItem( aPosition, aFilterList, aHotKeyCommandId ); + + if( !item ) + { + m_canvas->SetAbortRequest( false ); // Just in case the user aborted the context menu. + return NULL; + } + + // Cross probing to Pcbnew if a pin or a component is found + switch( item->Type() ) + { + case SCH_FIELD_T: + case LIB_FIELD_T: + LibItem = (SCH_COMPONENT*) item->GetParent(); + SendMessageToPCBNEW( item, LibItem ); + break; + + case SCH_COMPONENT_T: + LibItem = (SCH_COMPONENT*) item; + SendMessageToPCBNEW( item, LibItem ); + break; + + case LIB_PIN_T: + Pin = (LIB_PIN*) item; + LibItem = (SCH_COMPONENT*) LocateItem( aPosition, SCH_COLLECTOR::ComponentsOnly ); + break; + + default: + ; + } + + if( Pin ) + { + // Force display pin information (the previous display could be a component info) + MSG_PANEL_ITEMS items; + + Pin->GetMsgPanelInfo( items ); + + if( LibItem ) + items.push_back( MSG_PANEL_ITEM( LibItem->GetRef( m_CurrentSheet ), + LibItem->GetField( VALUE )->GetShownText(), DARKCYAN ) ); + + SetMsgPanel( items ); + + // Cross probing:2 - pin found, and send a locate pin command to Pcbnew (highlight net) + SendMessageToPCBNEW( Pin, LibItem ); + } + + return item; +} + + +SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, const KICAD_T aFilterList[], + int aHotKeyCommandId ) +{ + SCH_ITEM* item = NULL; + + m_collectedItems.Collect( GetScreen()->GetDrawItems(), aFilterList, aPosition ); + + if( m_collectedItems.GetCount() == 0 ) + { + ClearMsgPanel(); + } + else if( m_collectedItems.GetCount() == 1 ) + { + item = m_collectedItems[0]; + } + else + { + // There are certain combinations of items that do not need clarification such as + // a corner were two lines meet or all the items form a junction. + if( aHotKeyCommandId ) + { + switch( aHotKeyCommandId ) + { + case HK_DRAG: + if( m_collectedItems.IsCorner() || m_collectedItems.IsNode( false ) + || m_collectedItems.IsDraggableJunction() ) + { + item = m_collectedItems[0]; + } + default: + ; + } + } + + if( item == NULL ) + { + wxASSERT_MSG( m_collectedItems.GetCount() <= MAX_SELECT_ITEM_IDS, + wxT( "Select item clarification context menu size limit exceeded." ) ); + + wxMenu selectMenu; + wxMenuItem* title = new wxMenuItem( &selectMenu, wxID_NONE, _( "Clarify Selection" ) ); + + selectMenu.Append( title ); + selectMenu.AppendSeparator(); + + for( int i = 0; i < m_collectedItems.GetCount() && i < MAX_SELECT_ITEM_IDS; i++ ) + { + wxString text = m_collectedItems[i]->GetSelectMenuText(); + BITMAP_DEF xpm = m_collectedItems[i]->GetMenuImage(); + AddMenuItem( &selectMenu, ID_SELECT_ITEM_START + i, text, KiBitmap( xpm ) ); + } + + // Set to NULL in case user aborts the clarification context menu. + GetScreen()->SetCurItem( NULL ); + m_canvas->SetAbortRequest( true ); // Changed to false if an item is selected + PopupMenu( &selectMenu ); + m_canvas->MoveCursorToCrossHair(); + item = GetScreen()->GetCurItem(); + } + } + + GetScreen()->SetCurItem( item ); + + if( item ) + { + if( item->Type() == SCH_COMPONENT_T ) + ( (SCH_COMPONENT*) item )->SetCurrentSheetPath( &GetCurrentSheet() ); + + MSG_PANEL_ITEMS items; + item->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + } + else + { + ClearMsgPanel(); + } + + return item; +} + + +bool SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey ) +{ + bool eventHandled = true; + + // Filter out the 'fake' mouse motion after a keyboard movement + if( !aHotKey && m_movingCursorWithKeyboard ) + { + m_movingCursorWithKeyboard = false; + return false; + } + + // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed + // for next cursor position + // ( shift or ctrl key down are PAN command with mouse wheel) + bool snapToGrid = true; + + if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) ) + snapToGrid = false; + + // Cursor is left off grid only if no block in progress + if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + snapToGrid = true; + + wxPoint pos = aPosition; + wxPoint oldpos = GetCrossHairPosition(); + GeneralControlKeyMovement( aHotKey, &pos, snapToGrid ); + + // Update cursor position. + SetCrossHairPosition( pos, snapToGrid ); + RefreshCrossHair( oldpos, aPosition, aDC ); + + if( aHotKey ) + { + SCH_SCREEN* screen = GetScreen(); + + if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() ) + eventHandled = OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() ); + else + eventHandled = OnHotKey( aDC, aHotKey, aPosition, NULL ); + } + + UpdateStatusBar(); /* Display cursor coordinates info */ + + return eventHandled; +} + + +bool LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey ) +{ + bool eventHandled = true; + + // Filter out the 'fake' mouse motion after a keyboard movement + if( !aHotKey && m_movingCursorWithKeyboard ) + { + m_movingCursorWithKeyboard = false; + return false; + } + + // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed + // for next cursor position + // ( shift or ctrl key down are PAN command with mouse wheel) + bool snapToGrid = true; + + if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) ) + snapToGrid = false; + + // Cursor is left off grid only if no block in progress + if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + snapToGrid = true; + + wxPoint pos = aPosition; + wxPoint oldpos = GetCrossHairPosition(); + GeneralControlKeyMovement( aHotKey, &pos, snapToGrid ); + + // Update the cursor position. + SetCrossHairPosition( pos, snapToGrid ); + RefreshCrossHair( oldpos, aPosition, aDC ); + + if( aHotKey ) + { + eventHandled = OnHotKey( aDC, aHotKey, aPosition, NULL ); + } + + UpdateStatusBar(); + + return eventHandled; +} + + +bool LIB_VIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey ) +{ + bool eventHandled = true; + + // Filter out the 'fake' mouse motion after a keyboard movement + if( !aHotKey && m_movingCursorWithKeyboard ) + { + m_movingCursorWithKeyboard = false; + return false; + } + + wxPoint pos = aPosition; + wxPoint oldpos = GetCrossHairPosition(); + GeneralControlKeyMovement( aHotKey, &pos, true ); + + // Update cursor position. + SetCrossHairPosition( pos, true ); + RefreshCrossHair( oldpos, aPosition, aDC ); + + if( aHotKey ) + { + SCH_SCREEN* screen = GetScreen(); + + if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() ) + eventHandled = OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() ); + else + eventHandled = OnHotKey( aDC, aHotKey, aPosition, NULL ); + } + + UpdateStatusBar(); // Display cursor coordinates info. + + return eventHandled; +} diff --git a/eeschema/cross-probing.cpp b/eeschema/cross-probing.cpp new file mode 100644 index 00000000..f9b67e77 --- /dev/null +++ b/eeschema/cross-probing.cpp @@ -0,0 +1,214 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema/cross-probing.cpp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/** + * Execute a remote command sent by Pcbnew via a socket connection. + *

+ * When user selects a module or pin in Pcbnew, Eeschema shows that same + * component or pin and moves cursor on the item. The socket port used + * is #KICAD_SCH_PORT_SERVICE_NUMBER which defaults to 4243. + * + * Valid commands are: + * \li \c \$PART: \c "reference" Put cursor on component. + * \li \c \$PART: \c "reference" \c \$REF: \c "ref" Put cursor on component reference. + * \li \c \$PART: \c "reference" \c \$VAL: \c "value" Put cursor on component value. + * \li \c \$PART: \c "reference" \c \$PAD: \c "pin name" Put cursor on the component pin. + *

+ * @param cmdline = received command from Pcbnew + */ +void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) +{ + char line[1024]; + + strncpy( line, cmdline, sizeof(line) - 1 ); + line[ sizeof(line) - 1 ] = '\0'; + + char* idcmd = strtok( line, " \n\r" ); + char* text = strtok( NULL, "\"\n\r" ); + + if( (idcmd == NULL) || (text == NULL) ) + return; + + if( strcmp( idcmd, "$PART:" ) != 0 ) + return; + + wxString part_ref = FROM_UTF8( text ); + + /* look for a complement */ + idcmd = strtok( NULL, " \n\r" ); + + if( idcmd == NULL ) // component only + { + FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); + return; + } + + text = strtok( NULL, "\"\n\r" ); + + if( text == NULL ) + return; + + wxString msg = FROM_UTF8( text ); + + if( strcmp( idcmd, "$REF:" ) == 0 ) + { + FindComponentAndItem( part_ref, true, FIND_REFERENCE, msg, false ); + } + else if( strcmp( idcmd, "$VAL:" ) == 0 ) + { + FindComponentAndItem( part_ref, true, FIND_VALUE, msg, false ); + } + else if( strcmp( idcmd, "$PAD:" ) == 0 ) + { + FindComponentAndItem( part_ref, true, FIND_PIN, msg, false ); + } + else + { + FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); + } +} + + +std::string FormatProbeItem( EDA_ITEM* aComponent, SCH_COMPONENT* aPart ) +{ + // Cross probing to Pcbnew if a pin or a component is found + switch( aComponent->Type() ) + { + case SCH_FIELD_T: + case LIB_FIELD_T: + { + if( !aPart ) + break; + + return StrPrintf( "$PART: %s", TO_UTF8( aPart->GetField( REFERENCE )->GetText() ) ); + } + break; + + case SCH_COMPONENT_T: + aPart = (SCH_COMPONENT*) aComponent; + return StrPrintf( "$PART: %s", TO_UTF8( aPart->GetField( REFERENCE )->GetText() ) ); + + case LIB_PIN_T: + { + if( !aPart ) + break; + + LIB_PIN* pin = (LIB_PIN*) aComponent; + + if( pin->GetNumber() ) + { + wxString pinnum; + + pin->PinStringNum( pinnum ); + + return StrPrintf( "$PIN: %s $PART: %s", TO_UTF8( pinnum ), + TO_UTF8( aPart->GetField( REFERENCE )->GetText() ) ); + } + else + { + return StrPrintf( "$PART: %s", TO_UTF8( aPart->GetField( REFERENCE )->GetText() ) ); + } + } + break; + + default: + break; + } + + return ""; +} + + +void SCH_EDIT_FRAME::SendMessageToPCBNEW( EDA_ITEM* aComponent, SCH_COMPONENT* aPart ) +{ +#if 1 + wxASSERT( aComponent ); // fix the caller + +#else // WTF? + if( !aComponent ) // caller remains eternally stupid. + return; +#endif + + std::string packet = FormatProbeItem( aComponent, aPart ); + + if( packet.size() ) + { + if( Kiface().IsSingle() ) + SendCommand( MSG_TO_PCB, packet.c_str() ); + else + { + // Typically ExpressMail is going to be s-expression packets, but since + // we have existing interpreter of the cross probe packet on the other + // side in place, we use that here. + Kiway().ExpressMail( FRAME_PCB, MAIL_CROSS_PROBE, packet, this ); + } + } +} + + +void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) +{ + const std::string& payload = mail.GetPayload(); + + switch( mail.Command() ) + { + case MAIL_CROSS_PROBE: + ExecuteRemoteCommand( payload.c_str() ); + break; + + case MAIL_BACKANNOTATE_FOOTPRINTS: + try + { + backAnnotateFootprints( payload ); + } + catch( const IO_ERROR& ioe ) + { + DBG( printf( "%s: ioe:%s\n", __func__, TO_UTF8( ioe.errorText ) );) + } + break; + + default: + ; + } +} diff --git a/eeschema/dialog_erc_listbox.h b/eeschema/dialog_erc_listbox.h new file mode 100644 index 00000000..65bde96c --- /dev/null +++ b/eeschema/dialog_erc_listbox.h @@ -0,0 +1,120 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2015 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_ERC_LISTBOX_H +#define DIALOG_ERC_LISTBOX_H + +#include + +#include +#include +#include +#include + +/** + * Class ERC_HTML_LISTFRAME + * is used to display a DRC_ITEM_LIST. + */ +class ERC_HTML_LISTFRAME : public wxHtmlWindow +{ +private: + std::vector m_MarkerListReferences; // The pointers to markers shown in list + +public: + ERC_HTML_LISTFRAME( wxWindow* parent, wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0 ) : + wxHtmlWindow( parent, id, pos, size, style | wxHW_NO_SELECTION ) + { + } + + ~ERC_HTML_LISTFRAME() + { + } + + + /** + * Function AppendToList + * @param aItem The SCH_MARKER* to add to the current list which will be + * later displayed in the wxHtmlWindow + */ + void AppendToList( SCH_MARKER* aMarker ) + { + m_MarkerListReferences.push_back( aMarker ); + } + + /** + * Function DisplayList(); + * Build the Html marker list and show it + */ + void DisplayList() + { + wxString htmlpage; + + // for each marker, build a link like: + // text to click + // The "text to click" is the error name (first line of the full error text). + wxString marker_text; + + for( unsigned ii = 0; ii < m_MarkerListReferences.size(); ii++ ) + { + marker_text.Printf( wxT( "" ), ii ); + marker_text << m_MarkerListReferences[ii]->GetReporter().ShowHtml(); + marker_text.Replace( wxT( "

    " ), wxT( "
      " ), false ); + htmlpage += marker_text; + } + + SetPage( htmlpage ); + } + + /** + * Function GetItem + * returns a requested DRC_ITEM* or NULL. + */ + const SCH_MARKER* GetItem( unsigned aIndex ) + { + if( m_MarkerListReferences.size() > aIndex ) + { + return m_MarkerListReferences[ aIndex ]; + } + + return NULL; + } + + + /** + * Function ClearList + * deletes all items shown in the list. + * Does not erase markers in schematic + */ + void ClearList() + { + m_MarkerListReferences.clear(); + SetPage( wxEmptyString ); + } +}; + +#endif + +// DIALOG_ERC_LISTBOX_H diff --git a/eeschema/dialogs/dialog_annotate.cpp b/eeschema/dialogs/dialog_annotate.cpp new file mode 100644 index 00000000..5c8b002b --- /dev/null +++ b/eeschema/dialogs/dialog_annotate.cpp @@ -0,0 +1,320 @@ +/** + * @file dialog_annotate.cpp + * @brief Annotation dialog functions. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2012 jean-pierre Charras + * Copyright (C) 1992-2012 Kicad Developers, see change_log.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 +#include +#include + +#include +#include +#include + +#define KEY_ANNOTATE_SORT_OPTION wxT( "AnnotateSortOption" ) +#define KEY_ANNOTATE_ALGO_OPTION wxT( "AnnotateAlgoOption" ) +#define KEY_ANNOTATE_KEEP_OPEN_OPTION wxT( "AnnotateKeepOpenOption" ) +#define KEY_ANNOTATE_ASK_FOR_CONFIRMATION wxT( "AnnotateRequestConfirmation" ) + + +class wxConfigBase; + +namespace { + +/** + * Class DIALOG_ANNOTATE + */ +class DIALOG_ANNOTATE: public DIALOG_ANNOTATE_BASE +{ +public: + DIALOG_ANNOTATE( SCH_EDIT_FRAME* parent, wxString message ); + + +private: + SCH_EDIT_FRAME* m_Parent; + wxConfigBase* m_Config; + + /// Initialises member variables + void InitValues(); + void OnCancelClick( wxCommandEvent& event ); + void OnClearAnnotationCmpClick( wxCommandEvent& event ); + void OnApplyClick( wxCommandEvent& event ); + + // User functions: + bool GetLevel(); + bool GetResetItems(); + bool GetLockUnits(); + + /** + * Function GetSortOrder + * @return 0 if annotation by X position, + * 1 if annotation by Y position, + * 2 if annotation by value + */ + int GetSortOrder(); + + /** + * Function GetAnnotateAlgo + * @return 0 if annotation using first not used Id value + * 1 if annotation using first not used Id value inside sheet num * 100 to sheet num * 100 + 99 + * 2 if annotation using first nhot used Id value inside sheet num * 1000 to sheet num * 1000 + 999 + */ + int GetAnnotateAlgo(); + + bool GetAnnotateKeepOpen() + { + return m_cbKeepDlgOpen->GetValue(); + } + + bool GetAnnotateAskForConfirmation() + { + return m_cbAskForConfirmation->GetValue(); + } +}; + +} // anonymous namespace + + +DIALOG_ANNOTATE::DIALOG_ANNOTATE( SCH_EDIT_FRAME* parent, wxString message ) + : DIALOG_ANNOTATE_BASE( parent ) +{ + m_Parent = parent; + m_userMessage->SetLabelText( message ); + m_userMessage->Show( !message.empty() ); + + InitValues(); + Layout(); + GetSizer()->SetSizeHints( this ); + Centre(); +} + + +void DIALOG_ANNOTATE::InitValues() +{ + m_Config = Kiface().KifaceSettings(); + + if( m_Config ) + { + long option; + + m_Config->Read( KEY_ANNOTATE_SORT_OPTION, &option, 0L ); + switch( option ) + { + default: + case 0: + m_rbSortBy_X_Position->SetValue( 1 ); + break; + + case 1: + m_rbSortBy_Y_Position->SetValue( 1 ); + break; + + case 2: + m_rbUseIncremental->SetValue( 1 ); + break; + } + + m_Config->Read( KEY_ANNOTATE_ALGO_OPTION, &option, 0L ); + switch( option ) + { + default: + case 0: + m_rbUseIncremental->SetValue( 1 ); + break; + + case 1: + m_rbUseSheetNum->SetValue( 1 ); + break; + + case 2: + m_rbStartSheetNumLarge->SetValue( 1 ); + break; + } + + + m_Config->Read( KEY_ANNOTATE_KEEP_OPEN_OPTION, &option, 0L ); + m_cbKeepDlgOpen->SetValue( option ); + + + m_Config->Read( KEY_ANNOTATE_ASK_FOR_CONFIRMATION, &option, 1L ); + m_cbAskForConfirmation->SetValue( option ); + } + + annotate_down_right_bitmap->SetBitmap( KiBitmap( annotate_down_right_xpm ) ); + annotate_right_down_bitmap->SetBitmap( KiBitmap( annotate_right_down_xpm ) ); + + m_btnApply->SetDefault(); +} + + +void DIALOG_ANNOTATE::OnApplyClick( wxCommandEvent& event ) +{ + int response; + wxString message; + + if( m_Config ) + { + m_Config->Write( KEY_ANNOTATE_SORT_OPTION, GetSortOrder() ); + m_Config->Write( KEY_ANNOTATE_ALGO_OPTION, GetAnnotateAlgo() ); + m_Config->Write( KEY_ANNOTATE_KEEP_OPEN_OPTION, GetAnnotateKeepOpen() ); + m_Config->Write( KEY_ANNOTATE_ASK_FOR_CONFIRMATION, GetAnnotateAskForConfirmation() ); + } + + // Display a message info if we always ask for confirmation + // or if a reset of the previous annotation is asked. + bool promptUser = GetAnnotateAskForConfirmation(); + + if( GetResetItems() ) + { + if( GetLevel() ) + message += _( "Clear and annotate all of the components on the entire schematic?" ); + else + message += _( "Clear and annotate all of the components on the current sheet?" ); + promptUser = true; + } + else + { + if( GetLevel() ) + message += _( "Annotate only the unannotated components on the entire schematic?" ); + else + message += _( "Annotate only the unannotated components on the current sheet?" ); + } + + message += _( "\n\nThis operation will change the current annotation and cannot be undone." ); + + if( promptUser ) + { + // TODO(hzeller): ideally, this would be a wxMessageDialog that contains + // a checkbox asking the 'ask for confirmation' flag for better + // discoverability (and it should only show in the 'benign' case, so if + // !GetResetItems()) + response = wxMessageBox( message, wxT( "" ), wxICON_EXCLAMATION | wxOK | wxCANCEL ); + + if( response == wxCANCEL ) + return; + } + + m_Parent->AnnotateComponents( GetLevel(), (ANNOTATE_ORDER_T) GetSortOrder(), + (ANNOTATE_OPTION_T) GetAnnotateAlgo(), + GetResetItems() , true, GetLockUnits() ); + m_Parent->GetCanvas()->Refresh(); + + m_btnClear->Enable(); + + if( !GetAnnotateKeepOpen() ) + { + if( IsModal() ) + EndModal( wxID_OK ); + else + { + SetReturnCode( wxID_OK ); + this->Show( false ); + } + } +} + + +void DIALOG_ANNOTATE::OnClearAnnotationCmpClick( wxCommandEvent& event ) +{ + int response; + wxString message; + + if( GetLevel() ) + message = _( "Clear the existing annotation for the entire schematic?" ); + else + message = _( "Clear the existing annotation for the current sheet?" ); + + message += _( "\n\nThis operation will clear the existing annotation and cannot be undone." ); + response = wxMessageBox( message, wxT( "" ), wxICON_EXCLAMATION | wxOK | wxCANCEL ); + + if( response == wxCANCEL ) + return; + + m_Parent->DeleteAnnotation( GetLevel() ? false : true ); + m_btnClear->Enable( false ); +} + + +void DIALOG_ANNOTATE::OnCancelClick( wxCommandEvent& event ) +{ + if( IsModal() ) + EndModal( wxID_CANCEL ); + else + { + SetReturnCode( wxID_CANCEL ); + this->Show( false ); + } +} + + +bool DIALOG_ANNOTATE::GetLevel() +{ + return m_rbEntireSchematic->GetValue(); +} + + +bool DIALOG_ANNOTATE::GetResetItems() +{ + return m_rbResetAnnotation->GetValue() || m_rbResetButLock->GetValue(); +} + +bool DIALOG_ANNOTATE::GetLockUnits() +{ + return m_rbResetButLock->GetValue(); +} + +int DIALOG_ANNOTATE::GetSortOrder() +{ + if( m_rbSortBy_X_Position->GetValue() ) + return 0; + + if( m_rbSortBy_Y_Position->GetValue() ) + return 1; + + return 2; +} + + +int DIALOG_ANNOTATE::GetAnnotateAlgo() +{ + if( m_rbUseIncremental->GetValue() ) + return 0; + + if( m_rbUseSheetNum->GetValue() ) + return 1; + + return 2; +} + + +int InvokeDialogAnnotate( SCH_EDIT_FRAME* aCaller, wxString message ) +{ + DIALOG_ANNOTATE dlg( aCaller, message ); + + return dlg.ShowModal(); +} diff --git a/eeschema/dialogs/dialog_annotate_base.cpp b/eeschema/dialogs/dialog_annotate_base.cpp new file mode 100644 index 00000000..2ae59aac --- /dev/null +++ b/eeschema/dialogs/dialog_annotate_base.cpp @@ -0,0 +1,245 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_annotate_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_ANNOTATE_BASE::DIALOG_ANNOTATE_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bmainSizer; + bmainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bupperSizer; + bupperSizer = new wxBoxSizer( wxVERTICAL ); + + m_userMessage = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_userMessage->Wrap( 1 ); + m_userMessage->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bupperSizer->Add( m_userMessage, 0, wxALL, 5 ); + + m_staticTextScope = new wxStaticText( this, wxID_ANY, _("Scope"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextScope->Wrap( -1 ); + m_staticTextScope->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bupperSizer->Add( m_staticTextScope, 0, wxALL, 6 ); + + wxBoxSizer* bscopeOptSizer; + bscopeOptSizer = new wxBoxSizer( wxVERTICAL ); + + m_rbEntireSchematic = new wxRadioButton( this, ID_ENTIRE_SCHEMATIC, _("Use the &entire schematic"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + bscopeOptSizer->Add( m_rbEntireSchematic, 0, wxALL, 3 ); + + m_rbCurrPage = new wxRadioButton( this, ID_CURRENT_PAGE, _("Use the current &page only"), wxDefaultPosition, wxDefaultSize, 0 ); + bscopeOptSizer->Add( m_rbCurrPage, 0, wxALL, 3 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bscopeOptSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_rbKeepAnnotation = new wxRadioButton( this, ID_KEEP_ANNOTATION, _("&Keep existing annotation"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + bscopeOptSizer->Add( m_rbKeepAnnotation, 0, wxALL, 3 ); + + m_rbResetAnnotation = new wxRadioButton( this, ID_RESET_ANNOTATION, _("&Reset existing annotation"), wxDefaultPosition, wxDefaultSize, 0 ); + bscopeOptSizer->Add( m_rbResetAnnotation, 0, wxALL, 3 ); + + m_rbResetButLock = new wxRadioButton( this, ID_RESET_BUT_LOCK, _("R&eset, but do not swap any annotated multi-unit parts"), wxDefaultPosition, wxDefaultSize, 0 ); + bscopeOptSizer->Add( m_rbResetButLock, 0, wxALL, 3 ); + + + bupperSizer->Add( bscopeOptSizer, 0, wxEXPAND|wxLEFT, 25 ); + + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bupperSizer->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 ); + + m_staticTextOrder = new wxStaticText( this, wxID_ANY, _("Annotation Order"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextOrder->Wrap( -1 ); + m_staticTextOrder->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bupperSizer->Add( m_staticTextOrder, 0, wxALL, 6 ); + + wxBoxSizer* b_orderOptSizer; + b_orderOptSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerXpos; + bSizerXpos = new wxBoxSizer( wxHORIZONTAL ); + + m_rbSortBy_X_Position = new wxRadioButton( this, ID_SORT_BY_X_POSITION, _("Sort components by &X position"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + bSizerXpos->Add( m_rbSortBy_X_Position, 0, wxALL, 3 ); + + + bSizerXpos->Add( 0, 0, 1, wxEXPAND, 5 ); + + annotate_down_right_bitmap = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizerXpos->Add( annotate_down_right_bitmap, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 12 ); + + + b_orderOptSizer->Add( bSizerXpos, 0, wxEXPAND|wxRIGHT, 5 ); + + wxBoxSizer* bSizerYpos; + bSizerYpos = new wxBoxSizer( wxHORIZONTAL ); + + m_rbSortBy_Y_Position = new wxRadioButton( this, ID_SORT_BY_Y_POSITION, _("Sort components by &Y position"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerYpos->Add( m_rbSortBy_Y_Position, 0, wxALL, 3 ); + + + bSizerYpos->Add( 0, 0, 1, wxEXPAND, 5 ); + + annotate_right_down_bitmap = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizerYpos->Add( annotate_right_down_bitmap, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 12 ); + + + b_orderOptSizer->Add( bSizerYpos, 0, wxEXPAND|wxRIGHT, 5 ); + + + bupperSizer->Add( b_orderOptSizer, 0, wxEXPAND|wxLEFT, 25 ); + + m_staticline5 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bupperSizer->Add( m_staticline5, 0, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizerAnnotAlgo; + bSizerAnnotAlgo = new wxBoxSizer( wxVERTICAL ); + + m_staticTextAnnotateAlgo = new wxStaticText( this, wxID_ANY, _("Annotation Choice"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextAnnotateAlgo->Wrap( -1 ); + m_staticTextAnnotateAlgo->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizerAnnotAlgo->Add( m_staticTextAnnotateAlgo, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizer1AlgoChoice; + bSizer1AlgoChoice = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerChoiceInc; + bSizerChoiceInc = new wxBoxSizer( wxHORIZONTAL ); + + m_rbUseIncremental = new wxRadioButton( this, ID_SORT_BY_X_POSITION, _("Use first free number in schematic"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + bSizerChoiceInc->Add( m_rbUseIncremental, 0, wxALL, 3 ); + + + bSizerChoiceInc->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizer1AlgoChoice->Add( bSizerChoiceInc, 0, wxEXPAND|wxRIGHT, 5 ); + + wxBoxSizer* bSizerChoiceIncBySheet; + bSizerChoiceIncBySheet = new wxBoxSizer( wxHORIZONTAL ); + + m_rbUseSheetNum = new wxRadioButton( this, wxID_ANY, _("Start to sheet number*100 and use first free number"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerChoiceIncBySheet->Add( m_rbUseSheetNum, 0, wxALL, 3 ); + + + bSizerChoiceIncBySheet->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizer1AlgoChoice->Add( bSizerChoiceIncBySheet, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizerChoiceIncBySheetLarge; + bSizerChoiceIncBySheetLarge = new wxBoxSizer( wxHORIZONTAL ); + + m_rbStartSheetNumLarge = new wxRadioButton( this, wxID_ANY, _("Start to sheet number*1000 and use first free number"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerChoiceIncBySheetLarge->Add( m_rbStartSheetNumLarge, 0, wxALL, 3 ); + + + bSizerChoiceIncBySheetLarge->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizer1AlgoChoice->Add( bSizerChoiceIncBySheetLarge, 1, wxEXPAND, 5 ); + + + bSizerAnnotAlgo->Add( bSizer1AlgoChoice, 1, wxEXPAND|wxLEFT, 25 ); + + + bupperSizer->Add( bSizerAnnotAlgo, 0, wxEXPAND|wxRIGHT, 5 ); + + m_staticline4 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bupperSizer->Add( m_staticline4, 0, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizerDldOptions; + bSizerDldOptions = new wxBoxSizer( wxVERTICAL ); + + m_staticTextDlgOpts = new wxStaticText( this, wxID_ANY, _("Dialog"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDlgOpts->Wrap( -1 ); + m_staticTextDlgOpts->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizerDldOptions->Add( m_staticTextDlgOpts, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerDlgChoices; + bSizerDlgChoices = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerChoiceClose; + bSizerChoiceClose = new wxBoxSizer( wxHORIZONTAL ); + + m_cbKeepDlgOpen = new wxCheckBox( this, wxID_ANY, _("Keep this dialog open"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerChoiceClose->Add( m_cbKeepDlgOpen, 0, wxALL, 5 ); + + + bSizerChoiceClose->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizerDlgChoices->Add( bSizerChoiceClose, 0, wxEXPAND|wxRIGHT, 5 ); + + wxBoxSizer* bSizerChoiceSilentMode; + bSizerChoiceSilentMode = new wxBoxSizer( wxHORIZONTAL ); + + m_cbAskForConfirmation = new wxCheckBox( this, wxID_ANY, _("Always ask for confirmation"), wxDefaultPosition, wxDefaultSize, 0 ); + m_cbAskForConfirmation->SetValue(true); + bSizerChoiceSilentMode->Add( m_cbAskForConfirmation, 0, wxALL, 5 ); + + + bSizerChoiceSilentMode->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizerDlgChoices->Add( bSizerChoiceSilentMode, 1, wxEXPAND, 5 ); + + + bSizerDldOptions->Add( bSizerDlgChoices, 1, wxEXPAND|wxLEFT, 25 ); + + m_staticline41 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerDldOptions->Add( m_staticline41, 0, wxEXPAND | wxALL, 5 ); + + + bupperSizer->Add( bSizerDldOptions, 0, wxEXPAND|wxRIGHT, 5 ); + + wxBoxSizer* bButtonsSizer; + bButtonsSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_btnClose = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtonsSizer->Add( m_btnClose, 0, wxALL|wxEXPAND, 5 ); + + m_btnClear = new wxButton( this, ID_CLEAR_ANNOTATION_CMP, _("Clear Annotation"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtonsSizer->Add( m_btnClear, 0, wxALL|wxEXPAND, 5 ); + + m_btnApply = new wxButton( this, wxID_APPLY, _("Annotate"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtonsSizer->Add( m_btnApply, 0, wxALL|wxEXPAND, 5 ); + + + bupperSizer->Add( bButtonsSizer, 0, wxALIGN_CENTER_HORIZONTAL, 6 ); + + + bmainSizer->Add( bupperSizer, 1, wxALL|wxEXPAND, 6 ); + + + this->SetSizer( bmainSizer ); + this->Layout(); + bmainSizer->Fit( this ); + + // Connect Events + m_btnClose->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnCancelClick ), NULL, this ); + m_btnClear->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnClearAnnotationCmpClick ), NULL, this ); + m_btnApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnApplyClick ), NULL, this ); +} + +DIALOG_ANNOTATE_BASE::~DIALOG_ANNOTATE_BASE() +{ + // Disconnect Events + m_btnClose->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnCancelClick ), NULL, this ); + m_btnClear->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnClearAnnotationCmpClick ), NULL, this ); + m_btnApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ANNOTATE_BASE::OnApplyClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_annotate_base.fbp b/eeschema/dialogs/dialog_annotate_base.fbp new file mode 100644 index 00000000..bc759c05 --- /dev/null +++ b/eeschema/dialogs/dialog_annotate_base.fbp @@ -0,0 +1,2636 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_annotate_base + 1000 + none + 1 + dialog_annotate_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_ANNOTATE_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Annotate Schematic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bmainSizer + wxVERTICAL + none + + 6 + wxALL|wxEXPAND + 1 + + + bupperSizer + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_userMessage + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Scope + + 0 + + + 0 + + 1 + m_staticTextScope + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + wxEXPAND|wxLEFT + 0 + + + bscopeOptSizer + wxVERTICAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ENTIRE_SCHEMATIC + Use the &entire schematic + + 0 + + + 0 + + 1 + m_rbEntireSchematic + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CURRENT_PAGE + Use the current &page only + + 0 + + + 0 + + 1 + m_rbCurrPage + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_KEEP_ANNOTATION + &Keep existing annotation + + 0 + + + 0 + + 1 + m_rbKeepAnnotation + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_RESET_ANNOTATION + &Reset existing annotation + + 0 + + + 0 + + 1 + m_rbResetAnnotation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_RESET_BUT_LOCK + R&eset, but do not swap any annotated multi-unit parts + + 0 + + + 0 + + 1 + m_rbResetButLock + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Annotation Order + + 0 + + + 0 + + 1 + m_staticTextOrder + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + wxEXPAND|wxLEFT + 0 + + + b_orderOptSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerXpos + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_SORT_BY_X_POSITION + Sort components by &X position + + 0 + + + 0 + + 1 + m_rbSortBy_X_Position + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 12 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + Load From Resource; + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + annotate_down_right_bitmap + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerYpos + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_SORT_BY_Y_POSITION + Sort components by &Y position + + 0 + + + 0 + + 1 + m_rbSortBy_Y_Position + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 12 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + Load From Resource; + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + annotate_right_down_bitmap + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline5 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerAnnotAlgo + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Annotation Choice + + 0 + + + 0 + + 1 + m_staticTextAnnotateAlgo + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + wxEXPAND|wxLEFT + 1 + + + bSizer1AlgoChoice + wxVERTICAL + none + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerChoiceInc + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_SORT_BY_X_POSITION + Use first free number in schematic + + 0 + + + 0 + + 1 + m_rbUseIncremental + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 1 + + + bSizerChoiceIncBySheet + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Start to sheet number*100 and use first free number + + 0 + + + 0 + + 1 + m_rbUseSheetNum + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 1 + + + bSizerChoiceIncBySheetLarge + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Start to sheet number*1000 and use first free number + + 0 + + + 0 + + 1 + m_rbStartSheetNumLarge + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline4 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerDldOptions + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Dialog + + 0 + + + 0 + + 1 + m_staticTextDlgOpts + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + wxEXPAND|wxLEFT + 1 + + + bSizerDlgChoices + wxVERTICAL + none + + 5 + wxEXPAND|wxRIGHT + 0 + + + bSizerChoiceClose + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Keep this dialog open + + 0 + + + 0 + + 1 + m_cbKeepDlgOpen + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 1 + + + bSizerChoiceSilentMode + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Always ask for confirmation + + 0 + + + 0 + + 1 + m_cbAskForConfirmation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline41 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_HORIZONTAL + 0 + + + bButtonsSizer + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Close + + 0 + + + 0 + + 1 + m_btnClose + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CLEAR_ANNOTATION_CMP + Clear Annotation + + 0 + + + 0 + + 1 + m_btnClear + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnClearAnnotationCmpClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_APPLY + Annotate + + 0 + + + 0 + + 1 + m_btnApply + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnApplyClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_annotate_base.h b/eeschema/dialogs/dialog_annotate_base.h new file mode 100644 index 00000000..6ab17516 --- /dev/null +++ b/eeschema/dialogs/dialog_annotate_base.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 20 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_ANNOTATE_BASE_H__ +#define __DIALOG_ANNOTATE_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define ID_ENTIRE_SCHEMATIC 1000 +#define ID_CURRENT_PAGE 1001 +#define ID_KEEP_ANNOTATION 1002 +#define ID_RESET_ANNOTATION 1003 +#define ID_RESET_BUT_LOCK 1004 +#define ID_SORT_BY_X_POSITION 1005 +#define ID_SORT_BY_Y_POSITION 1006 +#define ID_CLEAR_ANNOTATION_CMP 1007 + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_ANNOTATE_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_ANNOTATE_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_userMessage; + wxStaticText* m_staticTextScope; + wxRadioButton* m_rbEntireSchematic; + wxRadioButton* m_rbCurrPage; + wxStaticLine* m_staticline1; + wxRadioButton* m_rbKeepAnnotation; + wxRadioButton* m_rbResetAnnotation; + wxRadioButton* m_rbResetButLock; + wxStaticLine* m_staticline2; + wxStaticText* m_staticTextOrder; + wxRadioButton* m_rbSortBy_X_Position; + wxStaticBitmap* annotate_down_right_bitmap; + wxRadioButton* m_rbSortBy_Y_Position; + wxStaticBitmap* annotate_right_down_bitmap; + wxStaticLine* m_staticline5; + wxStaticText* m_staticTextAnnotateAlgo; + wxRadioButton* m_rbUseIncremental; + wxRadioButton* m_rbUseSheetNum; + wxRadioButton* m_rbStartSheetNumLarge; + wxStaticLine* m_staticline4; + wxStaticText* m_staticTextDlgOpts; + wxCheckBox* m_cbKeepDlgOpen; + wxCheckBox* m_cbAskForConfirmation; + wxStaticLine* m_staticline41; + wxButton* m_btnClose; + wxButton* m_btnClear; + wxButton* m_btnApply; + + // Virtual event handlers, overide them in your derived class + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnClearAnnotationCmpClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnApplyClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_ANNOTATE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Annotate Schematic"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_ANNOTATE_BASE(); + +}; + +#endif //__DIALOG_ANNOTATE_BASE_H__ diff --git a/eeschema/dialogs/dialog_bom.cpp b/eeschema/dialogs/dialog_bom.cpp new file mode 100644 index 00000000..23bc74d7 --- /dev/null +++ b/eeschema/dialogs/dialog_bom.cpp @@ -0,0 +1,621 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr + * Copyright (C) 1992-2015 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 + */ + +/** + * @file eeschema/dialogs/dialog_bom.cpp + * @brief Dialog box for creating bom and other documents from generic netlist. + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOM_PLUGINS_KEY wxT("bom_plugins") +#define BOM_PLUGIN_SELECTED_KEY wxT("bom_plugin_selected") + +const char * s_bomHelpInfo = +#include +; + +#include + +using namespace T_BOMCFG_T; + +/** + * Class BOM_CFG_READER_PARSER + * holds data and functions pertinent to parsing a S-expression file + * for a WORKSHEET_LAYOUT. + */ +class BOM_CFG_READER_PARSER : public DIALOG_BOM_CFG_LEXER +{ + wxArrayString* m_pluginsList; + +public: + BOM_CFG_READER_PARSER( wxArrayString* aPlugins, + const char* aData, const wxString& aSource ); + void Parse() throw( PARSE_ERROR, IO_ERROR ); + +private: + void parsePlugin() throw( IO_ERROR, PARSE_ERROR ); +}; + +// PCB_PLOT_PARAMS_PARSER + +BOM_CFG_READER_PARSER::BOM_CFG_READER_PARSER( wxArrayString* aPlugins, + const char* aLine, + const wxString& aSource ) : + DIALOG_BOM_CFG_LEXER( aLine, aSource ) +{ + m_pluginsList = aPlugins; +} + + +void BOM_CFG_READER_PARSER::Parse() throw( PARSE_ERROR, IO_ERROR ) +{ + T token; + + while( ( token = NextTok() ) != T_RIGHT ) + { + if( token == T_EOF) + break; + + if( token == T_LEFT ) + token = NextTok(); + + if( token == T_plugins ) + continue; + + switch( token ) + { + case T_plugin: // Defines a new plugin + parsePlugin(); + break; + + default: +// Unexpected( CurText() ); + break; + } + } +} + +void BOM_CFG_READER_PARSER::parsePlugin() throw( IO_ERROR, PARSE_ERROR ) +{ + wxString title, command; + + NeedSYMBOLorNUMBER(); + title = FromUTF8(); + + T token; + while( ( token = NextTok() ) != T_RIGHT ) + { + if( token == T_EOF) + break; + + switch( token ) + { + case T_LEFT: + break; + + case T_cmd: + NeedSYMBOLorNUMBER(); + command = FromUTF8(); + NeedRIGHT(); + break; + + case T_opts: + while( ( token = NextTok() ) != T_RIGHT && token != T_EOF ); + break; + + default: + Unexpected( CurText() ); + break; + } + } + + if( ! title.IsEmpty() ) + { + m_pluginsList->Add( title ); + m_pluginsList->Add( command ); + } +} + +// The main dialog frame tu run scripts to build bom +class DIALOG_BOM : public DIALOG_BOM_BASE +{ +private: + SCH_EDIT_FRAME* m_parent; + // The list of scripts (or plugins): + // a script descr uses 2 lines: + // the first is the title + // the second is the command line + wxArrayString m_plugins; + wxConfigBase* m_config; // to store the "plugins" + +public: + // Constructor and destructor + DIALOG_BOM( SCH_EDIT_FRAME* parent ); + ~DIALOG_BOM(); + +private: + void OnPluginSelected( wxCommandEvent& event ); + void OnRunPlugin( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); + void OnHelp( wxCommandEvent& event ); + void OnAddPlugin( wxCommandEvent& event ); + void OnRemovePlugin( wxCommandEvent& event ); + void OnEditPlugin( wxCommandEvent& event ); + void OnCommandLineEdited( wxCommandEvent& event ); + void OnNameEdited( wxCommandEvent& event ); + + void pluginInit(); + void installPluginsList(); + + /** + * @return the Plugin filename from a command line + * @param aCommand = the command line + */ + wxString getPluginFileName( const wxString& aCommand ); + + /** + * display (when exists) the text found between the keyword "@package" + * (compatible with doxygen comments) + * and the end of comment block (""" in python", --> in xml) + */ + void displayPluginInfo( FILE * aFile, const wxString& aFilename ); + + /** + * Browse plugin files, and set m_CommandStringCtrl field + * @return a command line ro run the plugin + */ + wxString choosePlugin(); +}; + +// Create and show DIALOG_BOM. +int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller ) +{ + DIALOG_BOM dlg( aCaller ); + return dlg.ShowModal(); +} + +DIALOG_BOM::DIALOG_BOM( SCH_EDIT_FRAME* parent ) : + DIALOG_BOM_BASE( parent ) +{ + m_parent = parent; + m_config = Kiface().KifaceSettings(); + installPluginsList(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + +DIALOG_BOM::~DIALOG_BOM() +{ + // Save the plugin descriptions in config. + // the config stores only one string. + // plugins are saved inside a S expr: + // ( plugins + // ( plugin "plugin name" (cmd "command line") ) + // .... + // ) + + STRING_FORMATTER writer; + writer.Print( 0, "(plugins" ); + + for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 ) + { + writer.Print( 1, "(plugin %s (cmd %s))", + writer.Quotew( m_plugins[ii] ).c_str(), + writer.Quotew( m_plugins[ii+1] ).c_str() ); + } + + writer.Print( 0, ")" ); + + wxString list( FROM_UTF8( writer.GetString().c_str() ) ); + + m_config->Write( BOM_PLUGINS_KEY, list ); + + wxString active_plugin_name = m_lbPlugins->GetStringSelection( ); + m_config->Write( BOM_PLUGIN_SELECTED_KEY, active_plugin_name ); + +} + +/* Read the initialized plugins in config and fill the list + * of names + */ +void DIALOG_BOM::installPluginsList() +{ + wxString list, active_plugin_name; + m_config->Read( BOM_PLUGINS_KEY, &list ); + m_config->Read( BOM_PLUGIN_SELECTED_KEY, &active_plugin_name ); + + if( !list.IsEmpty() ) + { + BOM_CFG_READER_PARSER cfg_parser( &m_plugins, TO_UTF8( list ), + wxT( "plugins" ) ); + try + { + cfg_parser.Parse(); + } + catch( const IO_ERROR& ioe ) + { +// wxLogMessage( ioe.errorText ); + } + } + + // Populate list box + for( unsigned ii = 0; ii < m_plugins.GetCount(); ii+=2 ) + { + m_lbPlugins->Append( m_plugins[ii] ); + + if( active_plugin_name == m_plugins[ii] ) + m_lbPlugins->SetSelection( ii/2 ); + } + + pluginInit(); +} + +void DIALOG_BOM::OnPluginSelected( wxCommandEvent& event ) +{ + pluginInit(); +} + +#include +void DIALOG_BOM::pluginInit() +{ + int ii = m_lbPlugins->GetSelection(); + + if( ii < 0 ) + { + m_textCtrlName->SetValue( wxEmptyString ); + m_textCtrlCommand->SetValue( wxEmptyString ); + return; + } + + m_textCtrlName->SetValue( m_plugins[2 * ii] ); + m_textCtrlCommand->SetValue( m_plugins[(2 * ii)+1] ); + + wxString pluginName = getPluginFileName( m_textCtrlCommand->GetValue() ); + + if( pluginName.IsEmpty() ) + return; + + FILE* pluginFile = wxFopen( pluginName, "rt" ); + + if( pluginFile == NULL ) + { + wxString msg; + msg.Printf( _( "Failed to open file '%s'" ), GetChars( pluginName ) ); + DisplayError( this, msg ); + return; + } + + displayPluginInfo( pluginFile, pluginName ); +} + + +void DIALOG_BOM::displayPluginInfo( FILE * aFile, const wxString& aFilename ) +{ + m_Messages->Clear(); + + // display (when exists) the text found between the keyword "@package" + // (compatible with doxygen comments) + // and the end of comment block (""" in python", --> in xml) + + wxString data; + wxFFile fdata( aFile ); // dtor will close the file + + if( !fdata.ReadAll( &data ) ) + return; + + wxString header( wxT( "@package" ) ); + wxString endsection( wxT( "-->" ) ); // For xml + + wxFileName fn( aFilename ); + + if( fn.GetExt().IsSameAs( wxT("py"), false ) ) + endsection = wxT( "\"\"\"" ); + else if( !fn.GetExt().IsSameAs( wxT("xsl"), false ) ) + // If this is not a python file, we know nothing about file + // and the info cannot be found + return; + + // Extract substring between @package and """ + int strstart = data.Find( header ); + + if( strstart == wxNOT_FOUND ) + return; + + strstart += header.Length(); + int strend = data.find( endsection, strstart ); + + if( strend == wxNOT_FOUND) + return; + + // Remove empty line if any + while( data[strstart] < ' ' ) + strstart++; + + m_Messages->SetValue( data.SubString( strstart, strend-1 ) ); +} + +/** + * Function RunPlugin + * run the plugin command line + */ +void DIALOG_BOM::OnRunPlugin( wxCommandEvent& event ) +{ + wxFileName fn; + + // Calculate the xml netlist filename + fn = g_RootSheet->GetScreen()->GetFileName(); + + fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) ); + + fn.ClearExt(); + wxString fullfilename = fn.GetFullPath(); + m_parent->ClearMsgPanel(); + + wxString reportmsg; + WX_STRING_REPORTER reporter( &reportmsg ); + m_parent->SetNetListerCommand( m_textCtrlCommand->GetValue() ); + m_parent->CreateNetlist( -1, fullfilename, 0, &reporter ); + + m_Messages->SetValue( reportmsg ); +} + + +void DIALOG_BOM::OnCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +/** + * Function OnRemovePlugin + * Remove a plugin from the list + */ +void DIALOG_BOM::OnRemovePlugin( wxCommandEvent& event ) +{ + int ii = m_lbPlugins->GetSelection(); + + if( ii < 0 ) + return; + + m_lbPlugins->Delete( ii ); + + m_plugins.RemoveAt( 2*ii, 2 ); // Remove title and command line + + // Select the next item, if exists + if( (int)m_lbPlugins->GetCount() >= ii ) + ii = m_lbPlugins->GetCount() - 1; + + if( ii >= 0 ) + m_lbPlugins->SetSelection( ii ); + + pluginInit(); +} + +/** + * Function OnAddPlugin + * Add a new panel for a new netlist plugin + */ +void DIALOG_BOM::OnAddPlugin( wxCommandEvent& event ) +{ + wxString cmdLine = choosePlugin(); + + if( cmdLine.IsEmpty() ) + return; + + // Creates a new plugin entry + wxFileName fn( getPluginFileName( cmdLine ) ); + + wxString defaultName = fn.GetName(); + wxString name = wxGetTextFromUser( _("Plugin name in plugin list") , + _("Plugin name"), defaultName ); + + if( name.IsEmpty() ) + return; + + // Verify if it does not exists + for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 ) + { + if( name == m_plugins[ii] ) + { + wxMessageBox( _("This name already exists. Abort") ); + return; + } + } + + // Eppend the new plugin + m_plugins.Add( name ); + m_plugins.Add( wxEmptyString ); + m_lbPlugins->SetSelection( m_lbPlugins->GetCount() - 1 ); + m_lbPlugins->Append( name ); + m_lbPlugins->SetSelection( m_lbPlugins->GetCount() - 1 ); + m_textCtrlCommand->SetValue( cmdLine ); + + pluginInit(); +} + +/* + * Browse plugin files, and set m_CommandStringCtrl field + */ +wxString DIALOG_BOM::choosePlugin() +{ + wxString mask = wxT( "*" ); +#ifndef __WXMAC__ + wxString path = Pgm().GetExecutablePath(); +#else + wxString path = GetOSXKicadDataDir() + wxT( "/plugins" ); +#endif + + wxString fullFileName = EDA_FILE_SELECTOR( _( "Plugin files:" ), + path, + wxEmptyString, + wxEmptyString, + mask, + this, + wxFD_OPEN, + true ); + if( fullFileName.IsEmpty() ) + return wxEmptyString; + + // Creates a default command line, + // suitable to run the external tool xslproc or python + // The default command line depending on plugin extension, currently + // "xsl" or "exe" or "py" + wxString cmdLine; + wxFileName fn( fullFileName ); + wxString ext = fn.GetExt(); + + if( ext == wxT("xsl" ) ) + cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars( fullFileName ) ); + else if( ext == wxT("exe" ) || ext.IsEmpty() ) + cmdLine.Printf(wxT("\"%s\" < \"%%I\" > \"%%O\""), GetChars( fullFileName ) ); + else if( ext == wxT("py" ) || ext.IsEmpty() ) + cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars( fullFileName ) ); + else + cmdLine.Printf(wxT("\"%s\""), GetChars( fullFileName ) ); + + return cmdLine; +} + + +wxString DIALOG_BOM::getPluginFileName( const wxString& aCommand ) +{ + wxString pluginName; + + // Try to find the plugin name. + // This is possible if the name ends by .py or .xsl + int pos = -1; + + if( (pos = aCommand.Find( wxT(".py") )) != wxNOT_FOUND ) + pos += 2; + else if( (pos = aCommand.Find( wxT(".xsl") )) != wxNOT_FOUND ) + pos += 3; + + // the end of plugin name is at position pos. + if( pos > 0 ) + { + // Be sure this is the end of the name: the next char is " or space + int eos = aCommand[pos+1]; + + if( eos == ' '|| eos == '\"' ) + { + // search for the starting point of the name + int jj = pos-1; + while( jj >= 0 ) + if( aCommand[jj] != eos ) + jj--; + else + break; + + // extract the name + if( jj >= 0 ) + { + eos = aCommand[jj]; + + if( eos == ' '|| eos == '\"' ) // do not include delimiters + jj++; + + pluginName = aCommand.SubString( jj, pos ); + } + } + } + + // Using a format like %P is possible in plugin name, so expand it + wxString prj_dir = Prj().GetProjectPath(); + + if( prj_dir.EndsWith( '/' ) || prj_dir.EndsWith( '\\' ) ) + prj_dir.RemoveLast(); + + pluginName.Replace( wxT( "%P" ), prj_dir.GetData(), true ); + + return pluginName; +} + +void DIALOG_BOM::OnEditPlugin( wxCommandEvent& event ) +{ + wxString pluginName = getPluginFileName( m_textCtrlCommand->GetValue() ); + + if( pluginName.Length() <= 2 ) // if name != "" + { + wxMessageBox( _("Plugin file name not found. Cannot edit plugin file") ); + return; + } + + AddDelimiterString( pluginName ); + wxString editorname = Pgm().GetEditorName(); + + if( !editorname.IsEmpty() ) + ExecuteFile( this, editorname, pluginName ); + else + wxMessageBox( _("No text editor selected in KiCad. Please choose it") ); +} + +void DIALOG_BOM::OnHelp( wxCommandEvent& event ) +{ + HTML_MESSAGE_BOX help_Dlg( this, _("Bom Generation Help"), + wxDefaultPosition, wxSize( 750,550 ) ); + + wxString msg = FROM_UTF8(s_bomHelpInfo); + help_Dlg.m_htmlWindow->AppendToPage( msg ); + help_Dlg.ShowModal(); +} + +void DIALOG_BOM::OnCommandLineEdited( wxCommandEvent& event ) +{ + int ii = m_lbPlugins->GetSelection(); + + if( ii < 0 ) + return; + + m_plugins[(2 * ii)+1] = m_textCtrlCommand->GetValue(); +} + +void DIALOG_BOM::OnNameEdited( wxCommandEvent& event ) +{ + int ii = m_lbPlugins->GetSelection(); + + if( ii < 0 ) + return; + + m_plugins[2 * ii] = m_textCtrlName->GetValue(); + m_lbPlugins->SetString( ii, m_plugins[2 * ii] ); +} diff --git a/eeschema/dialogs/dialog_bom_base.cpp b/eeschema/dialogs/dialog_bom_base.cpp new file mode 100644 index 00000000..a32cc249 --- /dev/null +++ b/eeschema/dialogs/dialog_bom_base.cpp @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_bom_base.h" + +/////////////////////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE( DIALOG_BOM_BASE, DIALOG_SHIM ) + EVT_LISTBOX( wxID_ANY, DIALOG_BOM_BASE::_wxFB_OnPluginSelected ) + EVT_TEXT( IN_NAMELINE, DIALOG_BOM_BASE::_wxFB_OnNameEdited ) + EVT_BUTTON( ID_CREATE_BOM, DIALOG_BOM_BASE::_wxFB_OnRunPlugin ) + EVT_BUTTON( wxID_CANCEL, DIALOG_BOM_BASE::_wxFB_OnCancelClick ) + EVT_BUTTON( ID_HELP, DIALOG_BOM_BASE::_wxFB_OnHelp ) + EVT_BUTTON( ID_ADD_PLUGIN, DIALOG_BOM_BASE::_wxFB_OnAddPlugin ) + EVT_BUTTON( ID_REMOVEL_PLUGIN, DIALOG_BOM_BASE::_wxFB_OnRemovePlugin ) + EVT_BUTTON( wxID_ANY, DIALOG_BOM_BASE::_wxFB_OnEditPlugin ) + EVT_TEXT( ID_CMDLINE, DIALOG_BOM_BASE::_wxFB_OnCommandLineEdited ) +END_EVENT_TABLE() + +DIALOG_BOM_BASE::DIALOG_BOM_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bUpperSizer; + bUpperSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bLeftSizer; + bLeftSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticTextPluginTitle = new wxStaticText( this, wxID_ANY, _("Plugins"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPluginTitle->Wrap( -1 ); + bLeftSizer->Add( m_staticTextPluginTitle, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_lbPlugins = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + bLeftSizer->Add( m_lbPlugins, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextName = new wxStaticText( this, wxID_ANY, _("Name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextName->Wrap( -1 ); + bLeftSizer->Add( m_staticTextName, 0, wxRIGHT|wxLEFT, 5 ); + + m_textCtrlName = new wxTextCtrl( this, IN_NAMELINE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlName->SetMaxLength( 0 ); + bLeftSizer->Add( m_textCtrlName, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bUpperSizer->Add( bLeftSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bRightSizer; + bRightSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonNetlist = new wxButton( this, ID_CREATE_BOM, _("Generate"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonNetlist->SetDefault(); + bRightSizer->Add( m_buttonNetlist, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonCancel, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_buttonHelp = new wxButton( this, ID_HELP, _("Help"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonHelp, 0, wxALL|wxEXPAND, 5 ); + + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bRightSizer->Add( m_staticline2, 0, wxEXPAND|wxALL, 5 ); + + m_buttonAddPlugin = new wxButton( this, ID_ADD_PLUGIN, _("Add Plugin"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonAddPlugin, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_buttonDelPlugin = new wxButton( this, ID_REMOVEL_PLUGIN, _("Remove Plugin"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonDelPlugin, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_buttonEdit = new wxButton( this, wxID_ANY, _("Edit Plugin File"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonEdit, 0, wxALL|wxEXPAND, 5 ); + + + bUpperSizer->Add( bRightSizer, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bMainSizer->Add( bUpperSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bbottomSizer; + bbottomSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticTextCmd = new wxStaticText( this, wxID_ANY, _("Command line:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCmd->Wrap( -1 ); + bbottomSizer->Add( m_staticTextCmd, 0, wxRIGHT|wxLEFT, 5 ); + + m_textCtrlCommand = new wxTextCtrl( this, ID_CMDLINE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlCommand->SetMaxLength( 0 ); + m_textCtrlCommand->SetMinSize( wxSize( 380,-1 ) ); + + bbottomSizer->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bMainSizer->Add( bbottomSizer, 0, wxEXPAND, 5 ); + + m_staticTextInfo = new wxStaticText( this, wxID_ANY, _("Plugin Info:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextInfo->Wrap( -1 ); + bMainSizer->Add( m_staticTextInfo, 0, wxRIGHT|wxLEFT, 5 ); + + m_Messages = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY ); + bMainSizer->Add( m_Messages, 1, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +DIALOG_BOM_BASE::~DIALOG_BOM_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_bom_base.fbp b/eeschema/dialogs/dialog_bom_base.fbp new file mode 100644 index 00000000..f00eec75 --- /dev/null +++ b/eeschema/dialogs/dialog_bom_base.fbp @@ -0,0 +1,1445 @@ + + + + + + C++ + 0 + source_name + 0 + 0 + res + UTF-8 + table + dialog_bom_base + 1000 + none + 1 + dialog_bom_base + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_BOM_BASE + + 409,393 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Bill of Material + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bUpperSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bLeftSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Plugins + + 0 + + + 0 + + 1 + m_staticTextPluginTitle + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_lbPlugins + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + OnPluginSelected + + + + + + + + + + + + + + + + + + 5 + wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Name: + + 0 + + + 0 + + 1 + m_staticTextName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + IN_NAMELINE + + 0 + + 0 + + 0 + + 1 + m_textCtrlName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnNameEdited + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + bRightSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CREATE_BOM + Generate + + 0 + + + 0 + + 1 + m_buttonNetlist + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRunPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Close + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_HELP + Help + + 0 + + + 0 + + 1 + m_buttonHelp + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnHelp + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ADD_PLUGIN + Add Plugin + + 0 + + + 0 + + 1 + m_buttonAddPlugin + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_REMOVEL_PLUGIN + Remove Plugin + + 0 + + + 0 + + 1 + m_buttonDelPlugin + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRemovePlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Edit Plugin File + + 0 + + + 0 + + 1 + m_buttonEdit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnEditPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bbottomSizer + wxVERTICAL + none + + 5 + wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Command line: + + 0 + + + 0 + + 1 + m_staticTextCmd + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CMDLINE + + 0 + + 0 + + 0 + 380,-1 + 1 + m_textCtrlCommand + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnCommandLineEdited + + + + + + + + + + 5 + wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Plugin Info: + + 0 + + + 0 + + 1 + m_staticTextInfo + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_Messages + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_MULTILINE|wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_bom_base.h b/eeschema/dialogs/dialog_bom_base.h new file mode 100644 index 00000000..13571999 --- /dev/null +++ b/eeschema/dialogs/dialog_bom_base.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_BOM_BASE_H__ +#define __DIALOG_BOM_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_BOM_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_BOM_BASE : public DIALOG_SHIM +{ + DECLARE_EVENT_TABLE() + private: + + // Private event handlers + void _wxFB_OnPluginSelected( wxCommandEvent& event ){ OnPluginSelected( event ); } + void _wxFB_OnNameEdited( wxCommandEvent& event ){ OnNameEdited( event ); } + void _wxFB_OnRunPlugin( wxCommandEvent& event ){ OnRunPlugin( event ); } + void _wxFB_OnCancelClick( wxCommandEvent& event ){ OnCancelClick( event ); } + void _wxFB_OnHelp( wxCommandEvent& event ){ OnHelp( event ); } + void _wxFB_OnAddPlugin( wxCommandEvent& event ){ OnAddPlugin( event ); } + void _wxFB_OnRemovePlugin( wxCommandEvent& event ){ OnRemovePlugin( event ); } + void _wxFB_OnEditPlugin( wxCommandEvent& event ){ OnEditPlugin( event ); } + void _wxFB_OnCommandLineEdited( wxCommandEvent& event ){ OnCommandLineEdited( event ); } + + + protected: + enum + { + IN_NAMELINE = 1000, + ID_CREATE_BOM, + ID_HELP, + ID_ADD_PLUGIN, + ID_REMOVEL_PLUGIN, + ID_CMDLINE + }; + + wxStaticText* m_staticTextPluginTitle; + wxListBox* m_lbPlugins; + wxStaticText* m_staticTextName; + wxTextCtrl* m_textCtrlName; + wxButton* m_buttonNetlist; + wxButton* m_buttonCancel; + wxButton* m_buttonHelp; + wxStaticLine* m_staticline2; + wxButton* m_buttonAddPlugin; + wxButton* m_buttonDelPlugin; + wxButton* m_buttonEdit; + wxStaticText* m_staticTextCmd; + wxTextCtrl* m_textCtrlCommand; + wxStaticText* m_staticTextInfo; + wxTextCtrl* m_Messages; + + // Virtual event handlers, overide them in your derived class + virtual void OnPluginSelected( wxCommandEvent& event ) { event.Skip(); } + virtual void OnNameEdited( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRunPlugin( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnHelp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddPlugin( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemovePlugin( wxCommandEvent& event ) { event.Skip(); } + virtual void OnEditPlugin( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCommandLineEdited( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_BOM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Bill of Material"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 409,393 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_BOM_BASE(); + +}; + +#endif //__DIALOG_BOM_BASE_H__ diff --git a/eeschema/dialogs/dialog_bom_cfg.keywords b/eeschema/dialogs/dialog_bom_cfg.keywords new file mode 100644 index 00000000..8790280c --- /dev/null +++ b/eeschema/dialogs/dialog_bom_cfg.keywords @@ -0,0 +1,4 @@ +plugins +plugin +cmd +opts diff --git a/eeschema/dialogs/dialog_bom_help.html b/eeschema/dialogs/dialog_bom_help.html new file mode 100644 index 00000000..a254d884 --- /dev/null +++ b/eeschema/dialogs/dialog_bom_help.html @@ -0,0 +1,282 @@ + + + + + kicad help + + + + + + + + + + + + + + + + + + +

      1 - +Full documentation:

      +

      +The +Eeschema documentation describes +this intermediate netlist and gives examples
      See +also https://answers.launchpad.net/kicad/+faq/2265

      +

      2 - The intermediate Netlist File

      +

      +BOM +files (and netlist files) can be created from an Intermediate netlist +file created by Eeschema.

      +

      +This +file uses XML syntax and is called the intermediate netlist. The +intermediate netlist includes a large amount of data about your board +and because of this, it can be used with post-processing to create a +BOM or other reports.

      +

      +Depending +on the output (BOM or netlist), different subsets of the complete +Intermediate Netlist file will be used in the post-processing.

      +

      3 - Conversion to a new format

      +

      +By +applying a post-processing filter to the Intermediate netlist file +you can generate foreign netlist files as well as BOM files. Because +this conversion is a text to text transformation.

      +

      +this +post-processing filter can be written using Python, XSLT, +or any other tool capable of taking XML as input.

      +

      +XSLT +itself is a XML language very suitable for XML transformations. There +is a free program called xsltproc +that +you can download and install. The +xsltproc +program can be used to read the Intermediate XML netlist input file, +apply a +style-sheet to transform the input, and save the results in an output +file. Use of xsltproc requires a style-sheet file using XSLT +conventions. The full conversion process is handled +by +Eeschema, after it is configured once to run xsltproc in a specific +way.

      +

      +A +Python script is somewhat more easy to create.

      +

      4 - Initialization of the dialog window

      +

      +You +should add a new pluging (a script) in plugin list by clicking on the +Add Plugin button.

      +

      4.1 - Plugin Configuration Parameters

      +

      +The +Eeschema plug-in configuration dialog requires the following +information:

      +
        +
      • +

        + The + title: for instance, the name of the netlist format.

        +
      • +

        + The + command line to launch the converter (usually a script).

        +
      +

      +Once +you click on the generate button the following will happen:

      +
        +
      1. +

        + Eeschema + creates an intermediate netlist file *.xml, for instance test.xml.

        +
      2. +

        + Eeschema + runs the script from the command line to create the final output + file.

        +
      +

      4.2 - Generate netlist files with the command +line

      +

      +Assuming +we are using the program xsltproc.exe +to +apply the sheet style to the intermediate file, xsltproc.exe +is +executed with the following command.

      +

      +xsltproc.exe +-o < output filename > < style-sheet filename > < +input XML file to convert >

      +

      +On +Windows the command line is the following.
      f:/kicad/bin/xsltproc.exe +-o “%O” f:/kicad/bin/plugins/myconverter.xsl “%I”

      +

      +On +Linux the command becomes as following.
      xsltproc -o “%O” +/usr/local/kicad/bin/plugins/myconverter .xsl “%I”
      w
      here +myconverter.xsl +is +the style-sheet that you are applying.

      +

      +Do +not forget the double quotes +around +the file names, this allows them to have spaces after the +substitution by Eeschema.

      +

      +If +a Python script is used, the command line is something like +(depending on the Python script):

      +

      +python +f:/kicad/bin/plugins/bom-in-python/myconverter.py +“%I”“%O”
      or
      python
      +/usr/local/kicad/bin/plugins/bom-in-python/myconverter .xsl “%I” +“%O”
      +

      +

      +The +command line format accepts parameters for filenames:

      +

      +The +supported formatting parameters are.

      +
        +
      • +

        + %B + => base filename of selected output file, minus path and extension.

        +
      • +

        + %P + => project directory, without name and without trailing '/'.

        +
      • +

        + %I + => complete filename and path of the temporary input file + (the intermediate net file).

        +
      • +

        + %O + => complete filename and path (but without extension) of the user + chosen output file.

        +
      +

      +%I +will be replaced by the actual intermediate file name(usually +the full root sheet filename with extension “.xml”)
      %O +will +be replaced by the actual output file name (the full root sheet +filename minus extension).
      %B +will +be replaced by the actual output short file name +(the +short root sheet filename minus extension).
      %P +will +be replaced by the actual current project path.

      +

      4.3 - Command line format:

      +

      4.3.1 - Remark:

      +

      +Most +of time, the created file must have an extension, depending on its +type.
      Therefore you have to add to the option %O the +right file extension.

      +

      +For +instance:

      +
        +
      • +

        + %O.csv + to create a .csv file (comma separated value file).

        +
      • +

        + %O.html + to create a .html file.

        +
      • +

        + %O.bom + to create a .bom file.

        +
      +

      4.3.2 Example for xsltproc:

      +

      +The +command line format for xsltproc is the following:
      < path of +
      xsltproc > xsltproc +< xsltproc parameters >

      +

      +On +Windows:
      f:/kicad/bin/xsltproc.exe -o “%O.bom” +f:/kicad/bin/plugins/netlist_form_pads-pcb.xsl “%I”

      +

      +On +Linux:
      xsltproc -o “%O.bom” +/usr/local/kicad/bin/plugins/netlist_form_pads-pcb.xsl “%I”

      +

      +The +above examples assume +xsltproc +is installed on your PC under Windows xsl +exe +files +located in kicad/binplugins/.

      +

      +
      + +

      +

      4.3.3 Example for +python scripts:

      +

      +The +command line format for python is something like:
      python +< +script file name > < input filename > < +output filename >

      +

      +On +Windows:
      python.exe f:/kicad/bin/plugins +/bom-in-python/my_python_script.py%I” +“%O.html

      +

      +On +Linux:
      python /usr/local/kicad/bin/plugins +/bom-in-python/my_python_script.py%I” +“%O.csv

      +

      +Assuming +python is installed on your PC, and python scripts are located in +kicad/bin/plugins /bom-in-python/.

      +

      +
      + +

      + + diff --git a/eeschema/dialogs/dialog_choose_component.cpp b/eeschema/dialogs/dialog_choose_component.cpp new file mode 100644 index 00000000..3183c1d6 --- /dev/null +++ b/eeschema/dialogs/dialog_choose_component.cpp @@ -0,0 +1,409 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Henner Zeller + * Copyright (C) 2014 KiCad Developers, see change_log.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 + +#include +#include + +#include +#include +#include + +// Tree navigation helpers. +static wxTreeItemId GetPrevItem( const wxTreeCtrl& tree, const wxTreeItemId& item ); +static wxTreeItemId GetNextItem( const wxTreeCtrl& tree, const wxTreeItemId& item ); + +DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT( SCH_BASE_FRAME* aParent, const wxString& aTitle, + COMPONENT_TREE_SEARCH_CONTAINER* const aContainer, + int aDeMorganConvert ) + : DIALOG_CHOOSE_COMPONENT_BASE( aParent, wxID_ANY, aTitle ), m_search_container( aContainer ) +{ + m_parent = aParent; + m_deMorganConvert = aDeMorganConvert >= 0 ? aDeMorganConvert : 0; + m_external_browser_requested = false; + m_received_doubleclick_in_tree = false; + m_search_container->SetTree( m_libraryComponentTree ); + m_searchBox->SetFocus(); + m_componentDetails->SetEditable( false ); + m_componentView->SetLayoutDirection( wxLayout_LeftToRight ); + + m_libraryComponentTree->ScrollTo( m_libraryComponentTree->GetFocusedItem() ); + + // The tree showing libs and component uses a fixed font, + // because we want controle the position of some info when drawing the + // tree. Using tabs does not work very well (does not work on Windows) + wxFont font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); + m_libraryComponentTree->SetFont( wxFont( font.GetPointSize(), + wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ) ); + + // We have to call SetSizeHints to fix the minimal size of the dialog + // and its widgets. + // this line also fixes an issue on Linux Ubuntu using Unity (dialog not shown). + GetSizer()->SetSizeHints( this ); + + Centre(); +} + + +DIALOG_CHOOSE_COMPONENT::~DIALOG_CHOOSE_COMPONENT() +{ + m_search_container->SetTree( NULL ); +} + + +LIB_ALIAS* DIALOG_CHOOSE_COMPONENT::GetSelectedAlias( int* aUnit ) const +{ + return m_search_container->GetSelectedAlias( aUnit ); +} + + +void DIALOG_CHOOSE_COMPONENT::OnSearchBoxChange( wxCommandEvent& aEvent ) +{ + m_search_container->UpdateSearchTerm( m_searchBox->GetLineText( 0 ) ); + updateSelection(); + + // On Windows, but not on Linux, the focus is given to + // the m_libraryComponentTree, after modificatuons. + // We want the focus for m_searchBox. + // + // We cannot call SetFocus on Linux because it changes the current text selection + // and the text edit cursor position. +#ifdef __WINDOWS__ + m_searchBox->SetFocus(); +#endif +} + + +void DIALOG_CHOOSE_COMPONENT::OnSearchBoxEnter( wxCommandEvent& aEvent ) +{ + EndModal( wxID_OK ); // We are done. +} + + +void DIALOG_CHOOSE_COMPONENT::selectIfValid( const wxTreeItemId& aTreeId ) +{ + if( aTreeId.IsOk() && aTreeId != m_libraryComponentTree->GetRootItem() ) + m_libraryComponentTree->SelectItem( aTreeId ); +} + + +void DIALOG_CHOOSE_COMPONENT::OnInterceptSearchBoxKey( wxKeyEvent& aKeyStroke ) +{ + // Cursor up/down and partiallyi cursor are use to do tree navigation operations. + // This is done by intercepting some navigational keystrokes that normally would go to + // the text search box (which has the focus by default). That way, we are mostly keyboard + // operable. + // (If the tree has the focus, it can handle that by itself). + const wxTreeItemId sel = m_libraryComponentTree->GetSelection(); + + switch( aKeyStroke.GetKeyCode() ) + { + case WXK_UP: + selectIfValid( GetPrevItem( *m_libraryComponentTree, sel ) ); + break; + + case WXK_DOWN: + selectIfValid( GetNextItem( *m_libraryComponentTree, sel ) ); + break; + + // The following keys we can only hijack if they are not needed by the textbox itself. + + case WXK_LEFT: + if( m_searchBox->GetInsertionPoint() == 0 ) + m_libraryComponentTree->Collapse( sel ); + else + aKeyStroke.Skip(); // Use for original purpose: move cursor. + break; + + case WXK_RIGHT: + if( m_searchBox->GetInsertionPoint() >= (long) m_searchBox->GetLineText( 0 ).length() ) + m_libraryComponentTree->Expand( sel ); + else + aKeyStroke.Skip(); // Use for original purpose: move cursor. + break; + + default: + aKeyStroke.Skip(); // Any other key: pass on to search box directly. + break; + } +} + + +void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxTreeEvent& aEvent ) +{ + updateSelection(); +} + + +// Test strategy for OnDoubleClickTreeActivation()/OnTreeMouseUp() work around wxWidgets bug: +// - search for an item. +// - use the mouse to double-click on an item in the tree. +// -> The dialog should close, and the component should _not_ be immediately placed +void DIALOG_CHOOSE_COMPONENT::OnDoubleClickTreeActivation( wxTreeEvent& aEvent ) +{ + if( !updateSelection() ) + return; + + // Ok, got selection. We don't just end the modal dialog here, but + // wait for the MouseUp event to occur. Otherwise something (broken?) + // happens: the dialog will close and will deliver the 'MouseUp' event + // to the eeschema canvas, that will immediately place the component. + m_received_doubleclick_in_tree = true; +} + + +void DIALOG_CHOOSE_COMPONENT::OnTreeMouseUp( wxMouseEvent& aMouseEvent ) +{ + if( m_received_doubleclick_in_tree ) + EndModal( wxID_OK ); // We are done (see OnDoubleClickTreeSelect) + else + aMouseEvent.Skip(); // Let upstream handle it. +} + +// Test strategy to see if OnInterceptTreeEnter() works: +// - search for an item. +// - click into the tree once to set focus on tree; navigate. Press 'Enter' +// -> The dialog should close and the component be available to place. +void DIALOG_CHOOSE_COMPONENT::OnInterceptTreeEnter( wxKeyEvent& aEvent ) +{ + // We have to do some special handling for double-click on a tree-item because + // of some superfluous event delivery bug in wxWidgets (see OnDoubleClickTreeActivation()). + // In tree-activation, we assume we got a double-click and need to take special precaution + // that the mouse-up event is not delivered to the window one level up by going through + // a state-sequence OnDoubleClickTreeActivation() -> OnTreeMouseUp(). + + // Pressing 'Enter' within a tree will also call OnDoubleClickTreeActivation(), + // but since this is not due to the double-click and we have no way of knowing that it is + // not, we need to intercept the 'Enter' key before that to know that it is time to exit. + if( aEvent.GetKeyCode() == WXK_RETURN ) + EndModal( wxID_OK ); // Dialog is done. + else + aEvent.Skip(); // Let tree handle that key for navigation. +} + + +void DIALOG_CHOOSE_COMPONENT::OnStartComponentBrowser( wxMouseEvent& aEvent ) +{ + m_external_browser_requested = true; + EndModal( wxID_OK ); // We are done. +} + + +bool DIALOG_CHOOSE_COMPONENT::updateSelection() +{ + int unit = 0; + LIB_ALIAS* selection = m_search_container->GetSelectedAlias( &unit ); + + m_componentView->Refresh(); + + m_componentDetails->Clear(); + + if( selection == NULL ) + return false; + + m_componentDetails->Freeze(); + wxFont font_normal = m_componentDetails->GetFont(); + wxFont font_bold = m_componentDetails->GetFont(); + font_bold.SetWeight( wxFONTWEIGHT_BOLD ); + + wxTextAttr headline_attribute; + headline_attribute.SetFont( font_bold ); + wxTextAttr text_attribute; + text_attribute.SetFont( font_normal ); + + const wxString name = selection->GetName(); + + if ( !name.empty() ) + { + m_componentDetails->SetDefaultStyle( headline_attribute ); + m_componentDetails->AppendText( name ); + } + + const wxString description = selection->GetDescription(); + + if( !description.empty() ) + { + if ( !m_componentDetails->IsEmpty() ) + m_componentDetails->AppendText( wxT( "\n\n" ) ); + + m_componentDetails->SetDefaultStyle( headline_attribute ); + m_componentDetails->AppendText( _( "Description\n" ) ); + m_componentDetails->SetDefaultStyle( text_attribute ); + m_componentDetails->AppendText( description ); + } + + const wxString keywords = selection->GetKeyWords(); + + if( !keywords.empty() ) + { + if ( !m_componentDetails->IsEmpty() ) + m_componentDetails->AppendText( wxT( "\n\n" ) ); + + m_componentDetails->SetDefaultStyle( headline_attribute ); + m_componentDetails->AppendText( _( "Keywords\n" ) ); + m_componentDetails->SetDefaultStyle( text_attribute ); + m_componentDetails->AppendText( keywords ); + } + + if ( !selection->IsRoot() ) + { + LIB_PART* root_part = selection->GetPart(); + const wxString root_component_name( root_part ? root_part->GetName() : _( "Unknown" ) ); + + if ( !m_componentDetails->IsEmpty() ) + m_componentDetails->AppendText( wxT( "\n\n" ) ); + + m_componentDetails->SetDefaultStyle( headline_attribute ); + m_componentDetails->AppendText( _( "Alias of " ) ); + m_componentDetails->SetDefaultStyle( text_attribute ); + m_componentDetails->AppendText( root_component_name ); + } + + m_componentDetails->SetInsertionPoint( 0 ); // scroll up. + m_componentDetails->Thaw(); + + return true; +} + + +void DIALOG_CHOOSE_COMPONENT::OnHandlePreviewRepaint( wxPaintEvent& aRepaintEvent ) +{ + int unit = 0; + LIB_ALIAS* selection = m_search_container->GetSelectedAlias( &unit ); + LIB_PART* part = selection ? selection->GetPart() : NULL; + + // Don't draw anything (not even the background) if we don't have + // a part to show + if( !part ) + return; + + if( selection->IsRoot() ) + { + // just show the part directly + renderPreview( part, unit ); + } + else + { + // switch out the name temporarily for the alias name + wxString tmp( part->GetName() ); + part->SetName( selection->GetName() ); + + renderPreview( part, unit ); + + part->SetName( tmp ); + } +} + + +// Render the preview in our m_componentView. If this gets more complicated, we should +// probably have a derived class from wxPanel; but this keeps things local. +void DIALOG_CHOOSE_COMPONENT::renderPreview( LIB_PART* aComponent, int aUnit ) +{ + wxPaintDC dc( m_componentView ); + + const wxSize dc_size = dc.GetSize(); + + // Avoid rendering when either dimension is zero + if( dc_size.x == 0 || dc_size.y == 0 ) + return; + + GRResetPenAndBrush( &dc ); + + EDA_COLOR_T bgcolor = m_parent->GetDrawBgColor(); + + dc.SetBackground( bgcolor == BLACK ? *wxBLACK_BRUSH : *wxWHITE_BRUSH ); + dc.Clear(); + + if( aComponent == NULL ) + return; + + if( aUnit <= 0 ) + aUnit = 1; + + dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 ); + + // Find joint bounding box for everything we are about to draw. + EDA_RECT bBox = aComponent->GetBoundingBox( aUnit, m_deMorganConvert ); + const double xscale = (double) dc_size.x / bBox.GetWidth(); + const double yscale = (double) dc_size.y / bBox.GetHeight(); + const double scale = std::min( xscale, yscale ) * 0.85; + + dc.SetUserScale( scale, scale ); + + wxPoint offset = -bBox.Centre(); + + + aComponent->Draw( NULL, &dc, offset, aUnit, m_deMorganConvert, GR_COPY, + UNSPECIFIED_COLOR, DefaultTransform, true, true, false ); +} + + +static wxTreeItemId GetPrevItem( const wxTreeCtrl& tree, const wxTreeItemId& item ) +{ + wxTreeItemId prevItem = tree.GetPrevSibling( item ); + + if( !prevItem.IsOk() ) + { + prevItem = tree.GetItemParent( item ); + } + else if( tree.IsExpanded( prevItem ) ) + { + prevItem = tree.GetLastChild( prevItem ); + } + + return prevItem; +} + + +static wxTreeItemId GetNextItem( const wxTreeCtrl& tree, const wxTreeItemId& item ) +{ + wxTreeItemId nextItem; + + if( !item.IsOk() ) + return nextItem; // item is not valid: return a not valid wxTreeItemId + + if( tree.IsExpanded( item ) ) + { + wxTreeItemIdValue dummy; + nextItem = tree.GetFirstChild( item, dummy ); + } + else + { + wxTreeItemId root_cell= tree.GetRootItem(); + + // Walk up levels until we find one that has a next sibling. + for ( wxTreeItemId walk = item; walk.IsOk(); walk = tree.GetItemParent( walk ) ) + { + if( walk == root_cell ) // the root cell (not displayed) is reached + break; // Exit (calling GetNextSibling( root_cell ) crashes. + + nextItem = tree.GetNextSibling( walk ); + + if( nextItem.IsOk() ) + break; + } + } + + return nextItem; +} diff --git a/eeschema/dialogs/dialog_choose_component.h b/eeschema/dialogs/dialog_choose_component.h new file mode 100644 index 00000000..8d8ac24e --- /dev/null +++ b/eeschema/dialogs/dialog_choose_component.h @@ -0,0 +1,92 @@ +/* -*- c++ -*- + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Henner Zeller + * Copyright (C) 2014 KiCad Developers, see change_log.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_CHOOSE_COMPONENT_H +#define DIALOG_CHOOSE_COMPONENT_H + +#include + +class COMPONENT_TREE_SEARCH_CONTAINER; +class LIB_ALIAS; +class LIB_PART; +class wxTreeItemId; +class SCH_BASE_FRAME; + +class DIALOG_CHOOSE_COMPONENT : public DIALOG_CHOOSE_COMPONENT_BASE +{ + SCH_BASE_FRAME* m_parent; + COMPONENT_TREE_SEARCH_CONTAINER* const m_search_container; + int m_deMorganConvert; + bool m_external_browser_requested; + bool m_received_doubleclick_in_tree; + +public: + /** + * Create dialog to choose component. + * + * @param aParent a SCH_BASE_FRAME parent window. + * @param aTitle Dialog title. + * @param aSearchContainer The tree selection search container. Needs to be pre-populated + * This dialog does not take over ownership of this object. + * @param aDeMorganConvert preferred deMorgan conversion (TODO: should happen in dialog) + */ + DIALOG_CHOOSE_COMPONENT( SCH_BASE_FRAME* aParent, const wxString& aTitle, + COMPONENT_TREE_SEARCH_CONTAINER* const aSearchContainer, + int aDeMorganConvert ); + virtual ~DIALOG_CHOOSE_COMPONENT(); + + /** Function GetSelectedAlias + * To be called after this dialog returns from ShowModal(). + * + * @param aUnit if not NULL, the selected unit is filled in here. + * @return the alias that has been selected, or NULL if there is none. + */ + LIB_ALIAS* GetSelectedAlias( int* aUnit ) const; + + /** Function IsExternalBrowserSelected + * + * @return true, iff the user pressed the thumbnail view of the component to + * launch the component browser. + */ + bool IsExternalBrowserSelected() const { return m_external_browser_requested; } + +protected: + virtual void OnSearchBoxChange( wxCommandEvent& aEvent ); + virtual void OnSearchBoxEnter( wxCommandEvent& aEvent ); + virtual void OnInterceptSearchBoxKey( wxKeyEvent& aEvent ); + + virtual void OnTreeSelect( wxTreeEvent& aEvent ); + virtual void OnDoubleClickTreeActivation( wxTreeEvent& aEvent ); + virtual void OnInterceptTreeEnter( wxKeyEvent& aEvent ); + virtual void OnTreeMouseUp( wxMouseEvent& aMouseEvent ); + + virtual void OnStartComponentBrowser( wxMouseEvent& aEvent ); + virtual void OnHandlePreviewRepaint( wxPaintEvent& aRepaintEvent ); + +private: + bool updateSelection(); + void selectIfValid( const wxTreeItemId& aTreeId ); + void renderPreview( LIB_PART* aComponent, int aUnit ); +}; + +#endif /* DIALOG_CHOOSE_COMPONENT_H */ diff --git a/eeschema/dialogs/dialog_choose_component_base.cpp b/eeschema/dialogs/dialog_choose_component_base.cpp new file mode 100644 index 00000000..3d6f7ad9 --- /dev/null +++ b/eeschema/dialogs/dialog_choose_component_base.cpp @@ -0,0 +1,93 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_choose_component_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_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* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSearchSizer; + bSearchSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_searchLabel = new wxStaticText( this, wxID_ANY, _("Filter:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_searchLabel->Wrap( -1 ); + bSearchSizer->Add( m_searchLabel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + + m_searchBox = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + bSearchSizer->Add( m_searchBox, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizerMain->Add( bSearchSizer, 0, wxEXPAND, 5 ); + + m_libraryComponentTree = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT ); + m_libraryComponentTree->SetMinSize( wxSize( 400,200 ) ); + + bSizerMain->Add( m_libraryComponentTree, 1, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bSizerView; + bSizerView = new wxBoxSizer( wxHORIZONTAL ); + + m_componentView = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER ); + m_componentView->SetMinSize( wxSize( 200,200 ) ); + + bSizerView->Add( m_componentView, 4, wxEXPAND | wxALL, 5 ); + + m_componentDetails = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + m_componentDetails->SetMinSize( wxSize( 200,200 ) ); + + bSizerView->Add( m_componentDetails, 3, wxALL|wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerView, 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(); + + bSizerMain->Add( m_stdButtons, 0, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + m_searchBox->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptSearchBoxKey ), NULL, this ); + m_searchBox->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxChange ), NULL, this ); + m_searchBox->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxEnter ), NULL, this ); + m_libraryComponentTree->Connect( wxEVT_KEY_UP, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptTreeEnter ), NULL, this ); + m_libraryComponentTree->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this ); + m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeActivation ), NULL, this ); + m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this ); + m_componentView->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this ); + m_componentView->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnHandlePreviewRepaint ), NULL, this ); +} + +DIALOG_CHOOSE_COMPONENT_BASE::~DIALOG_CHOOSE_COMPONENT_BASE() +{ + // Disconnect Events + m_searchBox->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptSearchBoxKey ), NULL, this ); + m_searchBox->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxChange ), NULL, this ); + m_searchBox->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxEnter ), NULL, this ); + m_libraryComponentTree->Disconnect( wxEVT_KEY_UP, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptTreeEnter ), NULL, this ); + m_libraryComponentTree->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this ); + m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeActivation ), NULL, this ); + m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this ); + m_componentView->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this ); + m_componentView->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnHandlePreviewRepaint ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_choose_component_base.fbp b/eeschema/dialogs/dialog_choose_component_base.fbp new file mode 100644 index 00000000..57740013 --- /dev/null +++ b/eeschema/dialogs/dialog_choose_component_base.fbp @@ -0,0 +1,594 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_choose_component_base + 1000 + none + 1 + dialog_choose_component_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + -1,-1 + DIALOG_CHOOSE_COMPONENT_BASE + + 503,500 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bSearchSizer + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Filter: + + 0 + + + 0 + + 1 + m_searchLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + -1,-1 + + + 0 + + 1 + m_searchBox + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + OnInterceptSearchBoxKey + + + + + + + + + + + + + + + + + + + OnSearchBoxChange + OnSearchBoxEnter + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 400,200 + 1 + m_libraryComponentTree + 1 + + + protected + 1 + + Resizable + 1 + + wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT + + 0 + + + + + + + + + OnInterceptTreeEnter + + + + + OnTreeMouseUp + + + + + + + + + + + + + + + + + + + + OnDoubleClickTreeActivation + + + + + + + + + + OnTreeSelect + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerView + wxHORIZONTAL + none + + 5 + wxEXPAND | wxALL + 4 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 200,200 + 1 + m_componentView + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER + + + + + + + + + + OnStartComponentBrowser + + + + + + + OnHandlePreviewRepaint + + + + + + + + + + 5 + wxALL|wxEXPAND + 3 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 200,200 + 1 + m_componentDetails + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + wxTE_MULTILINE + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdButtons + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_choose_component_base.h b/eeschema/dialogs/dialog_choose_component_base.h new file mode 100644 index 00000000..afcebe61 --- /dev/null +++ b/eeschema/dialogs/dialog_choose_component_base.h @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_CHOOSE_COMPONENT_BASE_H__ +#define __DIALOG_CHOOSE_COMPONENT_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_CHOOSE_COMPONENT_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_CHOOSE_COMPONENT_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_searchLabel; + wxTextCtrl* m_searchBox; + wxTreeCtrl* m_libraryComponentTree; + wxPanel* m_componentView; + wxTextCtrl* m_componentDetails; + wxStdDialogButtonSizer* m_stdButtons; + wxButton* m_stdButtonsOK; + wxButton* m_stdButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnInterceptSearchBoxKey( wxKeyEvent& event ) { event.Skip(); } + virtual void OnSearchBoxChange( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSearchBoxEnter( wxCommandEvent& event ) { event.Skip(); } + virtual void OnInterceptTreeEnter( wxKeyEvent& event ) { event.Skip(); } + virtual void OnTreeMouseUp( wxMouseEvent& event ) { event.Skip(); } + virtual void OnDoubleClickTreeActivation( wxTreeEvent& event ) { event.Skip(); } + virtual void OnTreeSelect( wxTreeEvent& event ) { event.Skip(); } + virtual void OnStartComponentBrowser( wxMouseEvent& event ) { event.Skip(); } + virtual void OnHandlePreviewRepaint( wxPaintEvent& event ) { event.Skip(); } + + + public: + + DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 503,500 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_CHOOSE_COMPONENT_BASE(); + +}; + +#endif //__DIALOG_CHOOSE_COMPONENT_BASE_H__ diff --git a/eeschema/dialogs/dialog_color_config.cpp b/eeschema/dialogs/dialog_color_config.cpp new file mode 100644 index 00000000..c59b067e --- /dev/null +++ b/eeschema/dialogs/dialog_color_config.cpp @@ -0,0 +1,296 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 + */ + +/* Set up color Layers for Eeschema + */ + +#include +#include +#include + +#include + +#include + + +#define ID_COLOR_SETUP 1800 + +// Specify the width and height of every (color-displaying / bitmap) button +const int BUTT_SIZE_X = 16; +const int BUTT_SIZE_Y = 16; + + +/********************/ +/* Layer menu list. */ +/********************/ + +struct COLORBUTTON +{ + wxString m_Name; + int m_Layer; +}; + +struct BUTTONINDEX +{ + wxString m_Name; + COLORBUTTON* m_Buttons; +}; + +static COLORBUTTON generalColorButtons[] = { + { _( "Wire" ), LAYER_WIRE }, + { _( "Bus" ), LAYER_BUS }, + { _( "Junction" ), LAYER_JUNCTION }, + { _( "Label" ), LAYER_LOCLABEL }, + { _( "Global label" ), LAYER_GLOBLABEL }, + { _( "Net name" ), LAYER_NETNAM }, + { _( "Notes" ), LAYER_NOTES }, + { _( "No connect symbol" ), LAYER_NOCONNECT }, + { wxT( "" ), -1 } // Sentinel marking end of list. +}; + +static COLORBUTTON componentColorButtons[] = { + { _( "Body" ), LAYER_DEVICE }, + { _( "Body background" ), LAYER_DEVICE_BACKGROUND }, + { _( "Pin" ), LAYER_PIN }, + { _( "Pin number" ), LAYER_PINNUM }, + { _( "Pin name" ), LAYER_PINNAM }, + { _( "Reference" ), LAYER_REFERENCEPART }, + { _( "Value" ), LAYER_VALUEPART }, + { _( "Fields" ), LAYER_FIELDS }, + { wxT( "" ), -1 } // Sentinel marking end of list. +}; + +static COLORBUTTON sheetColorButtons[] = { + { _( "Sheet" ), LAYER_SHEET }, + { _( "Sheet file name" ), LAYER_SHEETFILENAME }, + { _( "Sheet name" ), LAYER_SHEETNAME }, + { _( "Sheet label" ), LAYER_SHEETLABEL }, + { _( "Hierarchical label" ),LAYER_HIERLABEL }, + { wxT( "" ), -1 } // Sentinel marking end of list. +}; + +static COLORBUTTON miscColorButtons[] = { + { _( "ERC warning" ), LAYER_ERC_WARN }, + { _( "ERC error" ), LAYER_ERC_ERR }, + { _( "Grid" ), LAYER_GRID }, + { wxT( "" ), -1 } // Sentinel marking end of list. +}; + + +static BUTTONINDEX buttonGroups[] = { + { _( "General" ), generalColorButtons }, + { _( "Component" ), componentColorButtons }, + { _( "Sheet" ), sheetColorButtons }, + { _( "Miscellaneous" ), miscColorButtons }, + { wxT( "" ), NULL } +}; + + +static EDA_COLOR_T currentColors[ LAYERSCH_ID_COUNT ]; + + +DIALOG_COLOR_CONFIG::DIALOG_COLOR_CONFIG( EDA_DRAW_FRAME* aParent ) : + DIALOG_COLOR_CONFIG_BASE( aParent ) +{ + m_parent = aParent; + CreateControls(); + + GetSizer()->SetSizeHints( this ); +} + + +void DIALOG_COLOR_CONFIG::CreateControls() +{ + wxStaticText* label; + int buttonId = 1800; + + BUTTONINDEX* groups = buttonGroups; + wxBoxSizer* columnBoxSizer = NULL; + + while( groups->m_Buttons != NULL ) + { + COLORBUTTON* buttons = groups->m_Buttons; + + columnBoxSizer = new wxBoxSizer( wxVERTICAL ); + m_mainBoxSizer->Add( columnBoxSizer, 1, wxALIGN_TOP | wxLEFT | wxTOP, 5 ); + wxBoxSizer* rowBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + columnBoxSizer->Add( rowBoxSizer, 0, wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 ); + + // Add a text string to identify the column of color select buttons. + label = new wxStaticText( this, wxID_ANY, groups->m_Name ); + + // Make the column label font bold. + wxFont font( label->GetFont() ); + font.SetWeight( wxFONTWEIGHT_BOLD ); + label->SetFont( font ); + + rowBoxSizer->Add( label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 ); + + while( buttons->m_Layer >= 0 ) + { + rowBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + columnBoxSizer->Add( rowBoxSizer, 0, wxGROW | wxALL, 0 ); + + wxMemoryDC iconDC; + wxBitmap bitmap( BUTT_SIZE_X, BUTT_SIZE_Y ); + + iconDC.SelectObject( bitmap ); + + EDA_COLOR_T color = GetLayerColor( LAYERSCH_ID( buttons->m_Layer ) ); + currentColors[ buttons->m_Layer ] = color; + + iconDC.SetPen( *wxBLACK_PEN ); + + wxBrush brush; + ColorSetBrush( &brush, color ); + brush.SetStyle( wxBRUSHSTYLE_SOLID ); + iconDC.SetBrush( brush ); + iconDC.DrawRectangle( 0, 0, BUTT_SIZE_X, BUTT_SIZE_Y ); + + wxBitmapButton* bitmapButton = new wxBitmapButton( + this, buttonId, bitmap, wxDefaultPosition, + wxSize( BUTT_SIZE_X+8, BUTT_SIZE_Y+6 ) ); + bitmapButton->SetClientData( (void*) buttons ); + + rowBoxSizer->Add( bitmapButton, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxBOTTOM, 5 ); + + label = new wxStaticText( this, wxID_ANY, wxGetTranslation( buttons->m_Name ) ); + rowBoxSizer->Add( label, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxBOTTOM, 5 ); + buttonId += 1; + buttons++; + } + + groups++; + } + + Connect( 1800, buttonId - 1, wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler( DIALOG_COLOR_CONFIG::SetColor ) ); + + wxArrayString selBgColorStrings; + selBgColorStrings.Add( _( "White" ) ); + selBgColorStrings.Add( _( "Black" ) ); + m_SelBgColor = new wxRadioBox( this, wxID_ANY, _( "Background Color" ), + wxDefaultPosition, wxDefaultSize, + selBgColorStrings, 1, wxRA_SPECIFY_COLS ); + m_SelBgColor->SetSelection( ( m_parent->GetDrawBgColor() == BLACK ) ? 1 : 0 ); + + if( columnBoxSizer ) + { + // Add a spacer to improve appearance. + columnBoxSizer->AddSpacer( 5 ); + columnBoxSizer->Add( m_SelBgColor, 1, wxGROW | wxRIGHT | wxTOP | wxBOTTOM, 5 ); + } + + currentColors[ LAYER_BACKGROUND ] = m_parent->GetDrawBgColor(); + + // Dialog now needs to be resized, but the associated command is found elsewhere. +} + + +void DIALOG_COLOR_CONFIG::SetColor( wxCommandEvent& event ) +{ + wxBitmapButton* button = (wxBitmapButton*) event.GetEventObject(); + + wxCHECK_RET( button != NULL, wxT( "Color button event object is NULL." ) ); + + COLORBUTTON* colorButton = (COLORBUTTON*) button->GetClientData(); + + wxCHECK_RET( colorButton != NULL, wxT( "Client data not set for color button." ) ); + + EDA_COLOR_T color = DisplayColorFrame( this, colorButton->m_Layer ); + + if( color < 0 || currentColors[ colorButton->m_Layer ] == color ) + return; + + currentColors[ colorButton->m_Layer ] = color; + + wxMemoryDC iconDC; + + wxBitmap bitmap = button->GetBitmapLabel(); + iconDC.SelectObject( bitmap ); + iconDC.SetPen( *wxBLACK_PEN ); + + wxBrush brush; + + ColorSetBrush( &brush, color); + + brush.SetStyle( wxBRUSHSTYLE_SOLID ); + + iconDC.SetBrush( brush ); + iconDC.DrawRectangle( 0, 0, BUTT_SIZE_X, BUTT_SIZE_Y ); + button->SetBitmapLabel( bitmap ); + button->Refresh(); + + Refresh( false ); +} + + +bool DIALOG_COLOR_CONFIG::TransferDataFromWindow() +{ + bool warning = false; + + // Check for color conflicts with background color to give user a chance to bail + // out before making changes. + + EDA_COLOR_T bgcolor = WHITE; + + if( m_SelBgColor->GetSelection() > 0 ) + bgcolor = BLACK; + + for( LAYERSCH_ID clyr = LAYER_WIRE; clyr < LAYERSCH_ID_COUNT; ++clyr ) + { + if( bgcolor == currentColors[ clyr ] && clyr != LAYER_BACKGROUND ) + { + warning = true; + break; + } + } + + // Prompt the user if an item has the same color as the background + // because this item cannot be seen: + if( warning ) + { + if( wxMessageBox( _( "Some items have the same color as the background\n" + "and they will not be seen on the screen. Are you\n" + "sure you want to use these colors?" ), + _( "Warning" ), + wxYES_NO | wxICON_QUESTION, this ) == wxNO ) + return false; + } + + // Update color of background + m_parent->SetDrawBgColor( bgcolor ); + currentColors[ LAYER_BACKGROUND ] = bgcolor; + + + for( LAYERSCH_ID clyr = LAYER_WIRE; clyr < LAYERSCH_ID_COUNT; ++clyr ) + { + SetLayerColor( currentColors[ clyr ], clyr ); + } + + m_parent->SetGridColor( GetLayerColor( LAYER_GRID ) ); + m_parent->GetCanvas()->Refresh(); + + return true; +} diff --git a/eeschema/dialogs/dialog_color_config.h b/eeschema/dialogs/dialog_color_config.h new file mode 100644 index 00000000..0f073679 --- /dev/null +++ b/eeschema/dialogs/dialog_color_config.h @@ -0,0 +1,58 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 G. Harland + * Copyright (C) 1992-2015 KiCad Developers, see CHANGELOG.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_COLOR_CONFIG_H_ +#define DIALOG_COLOR_CONFIG_H_ + +#include + + +class wxBoxSizer; +class wxStaticLine; +class wxStdDialogButtonSizer; + + +/***********************************************/ +/* Derived class for the frame color settings. */ +/***********************************************/ + +class DIALOG_COLOR_CONFIG : public DIALOG_COLOR_CONFIG_BASE +{ +private: + EDA_DRAW_FRAME* m_parent; + wxRadioBox* m_SelBgColor; + + // Creates the controls and sizers + void CreateControls(); + + void SetColor( wxCommandEvent& aEvent ); + +public: + // Constructors and destructor + DIALOG_COLOR_CONFIG( EDA_DRAW_FRAME* aParent ); + + bool TransferDataFromWindow(); +}; + +#endif // DIALOG_COLOR_CONFIG_H_ diff --git a/eeschema/dialogs/dialog_color_config_base.cpp b/eeschema/dialogs/dialog_color_config_base.cpp new file mode 100644 index 00000000..8991523b --- /dev/null +++ b/eeschema/dialogs/dialog_color_config_base.cpp @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_color_config_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_COLOR_CONFIG_BASE::DIALOG_COLOR_CONFIG_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bmainSizer; + bmainSizer = new wxBoxSizer( wxVERTICAL ); + + m_mainBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + + + bmainSizer->Add( m_mainBoxSizer, 1, wxEXPAND, 5 ); + + m_staticline = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bmainSizer->Add( m_staticline, 0, wxEXPAND | wxALL, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerApply = new wxButton( this, wxID_APPLY ); + m_sdbSizer->AddButton( m_sdbSizerApply ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + bmainSizer->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxALL, 5 ); + + + this->SetSizer( bmainSizer ); + this->Layout(); + bmainSizer->Fit( this ); + + this->Centre( wxBOTH ); +} + +DIALOG_COLOR_CONFIG_BASE::~DIALOG_COLOR_CONFIG_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_color_config_base.fbp b/eeschema/dialogs/dialog_color_config_base.fbp new file mode 100644 index 00000000..d739b579 --- /dev/null +++ b/eeschema/dialogs/dialog_color_config_base.fbp @@ -0,0 +1,217 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_color_config_base + 1000 + none + 1 + dialog_color_config_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_COLOR_CONFIG_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + EESchema Colors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bmainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + m_mainBoxSizer + wxHORIZONTAL + protected + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_color_config_base.h b/eeschema/dialogs/dialog_color_config_base.h new file mode 100644 index 00000000..83697b11 --- /dev/null +++ b/eeschema/dialogs/dialog_color_config_base.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_COLOR_CONFIG_BASE_H__ +#define __DIALOG_COLOR_CONFIG_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_COLOR_CONFIG_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_COLOR_CONFIG_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxBoxSizer* m_mainBoxSizer; + wxStaticLine* m_staticline; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerApply; + wxButton* m_sdbSizerCancel; + + public: + + DIALOG_COLOR_CONFIG_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("EESchema Colors"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_COLOR_CONFIG_BASE(); + +}; + +#endif //__DIALOG_COLOR_CONFIG_BASE_H__ diff --git a/eeschema/dialogs/dialog_edit_component_in_lib.cpp b/eeschema/dialogs/dialog_edit_component_in_lib.cpp new file mode 100644 index 00000000..d7c58a2c --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_lib.cpp @@ -0,0 +1,579 @@ +/** + * @file dialog_edit_component_in_lib.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include // for ID_POPUP_SCH_SELECT_UNIT_CMP_MAX and ID_POPUP_SCH_SELECT_UNIT1 + +#include + +int DIALOG_EDIT_COMPONENT_IN_LIBRARY::m_lastOpenedPage = 0; + +DIALOG_EDIT_COMPONENT_IN_LIBRARY::DIALOG_EDIT_COMPONENT_IN_LIBRARY( LIB_EDIT_FRAME* aParent ): + DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE( aParent ) +{ + m_Parent = aParent; + m_RecreateToolbar = false; + + initDlg(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +DIALOG_EDIT_COMPONENT_IN_LIBRARY::~DIALOG_EDIT_COMPONENT_IN_LIBRARY() +{ + m_lastOpenedPage = m_NoteBook->GetSelection( ); +} + +/* Initialize state of check boxes and texts +*/ +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::initDlg() +{ + m_AliasLocation = -1; + + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL ) + { + SetTitle( _( "Library Component Properties" ) ); + return; + } + + wxString title; + bool isRoot = m_Parent->GetAliasName().CmpNoCase( component->GetName() ) == 0; + + if( !isRoot ) + { + title.Printf( _( "Properties for %s (alias of %s)" ), + GetChars( m_Parent->GetAliasName() ), + GetChars( component->GetName() ) ); + } + else + title.Printf( _( "Properties for %s" ), GetChars( component->GetName() ) ); + + SetTitle( title ); + InitPanelDoc(); + InitBasicPanel(); + + if( isRoot && component->GetAliasCount() == 1 ) + m_ButtonDeleteAllAlias->Enable( false ); + + /* Place list of alias names in listbox */ + m_PartAliasListCtrl->Append( component->GetAliasNames( false ) ); + + if( component->GetAliasCount() <= 1 ) + { + m_ButtonDeleteAllAlias->Enable( false ); + m_ButtonDeleteOneAlias->Enable( false ); + } + + /* Read the Footprint Filter list */ + m_FootprintFilterListBox->Append( component->GetFootPrints() ); + + if( component->GetFootPrints().GetCount() == 0 ) + { + m_ButtonDeleteAllFootprintFilter->Enable( false ); + m_ButtonDeleteOneFootprintFilter->Enable( false ); + m_buttonEditOneFootprintFilter->Enable( false ); + } + + m_NoteBook->SetSelection( m_lastOpenedPage ); + + m_stdSizerButtonOK->SetDefault(); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitPanelDoc() +{ + LIB_ALIAS* alias; + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL ) + return; + + wxString aliasname = m_Parent->GetAliasName(); + + if( aliasname.IsEmpty() ) + return; + + alias = component->GetAlias( aliasname ); + + if( alias != NULL ) + { + m_DocCtrl->SetValue( alias->GetDescription() ); + m_KeywordsCtrl->SetValue( alias->GetKeyWords() ); + m_DocfileCtrl->SetValue( alias->GetDocFileName() ); + } +} + + +/* + * create the basic panel for component properties editing + */ +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitBasicPanel() +{ + LIB_PART* component = m_Parent->GetCurPart(); + + if( m_Parent->GetShowDeMorgan() ) + m_AsConvertButt->SetValue( true ); + + int maxUnits = ID_POPUP_SCH_SELECT_UNIT_CMP_MAX - ID_POPUP_SCH_SELECT_UNIT1; + m_SelNumberOfUnits->SetRange (1, maxUnits ); + + m_staticTextNbUnits->SetLabel( wxString::Format( + _( "Number of Units (max allowed %d)" ), maxUnits ) ); + + + /* Default values for a new component. */ + if( component == NULL ) + { + m_ShowPinNumButt->SetValue( true ); + m_ShowPinNameButt->SetValue( true ); + m_PinsNameInsideButt->SetValue( true ); + m_SelNumberOfUnits->SetValue( 1 ); + m_SetSkew->SetValue( 40 ); + m_OptionPower->SetValue( false ); + m_OptionPartsLocked->SetValue( false ); + return; + } + + m_ShowPinNumButt->SetValue( component->ShowPinNumbers() ); + m_ShowPinNameButt->SetValue( component->ShowPinNames() ); + m_PinsNameInsideButt->SetValue( component->GetPinNameOffset() != 0 ); + m_SelNumberOfUnits->SetValue( component->GetUnitCount() ); + m_SetSkew->SetValue( component->GetPinNameOffset() ); + m_OptionPower->SetValue( component->IsPower() ); + m_OptionPartsLocked->SetValue( component->UnitsLocked() && component->GetUnitCount() > 1 ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnOkClick( wxCommandEvent& event ) +{ + /* Update the doc, keyword and doc filename strings */ + LIB_ALIAS* alias; + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL ) + { + EndModal( wxID_CANCEL ); + return; + } + + m_Parent->SaveCopyInUndoList( component ); + + alias = component->GetAlias( m_Parent->GetAliasName() ); + + wxCHECK_RET( alias != NULL, + wxT( "Alias \"" ) + m_Parent->GetAliasName() + wxT( "\" of component \"" ) + + component->GetName() + wxT( "\" does not exist." ) ); + + alias->SetDescription( m_DocCtrl->GetValue() ); + alias->SetKeyWords( m_KeywordsCtrl->GetValue() ); + alias->SetDocFileName( m_DocfileCtrl->GetValue() ); + + component->SetAliases( m_PartAliasListCtrl->GetStrings() ); + + int unitCount = m_SelNumberOfUnits->GetValue(); + ChangeNbUnitsPerPackage( unitCount ); + + if( m_AsConvertButt->GetValue() ) + { + if( !m_Parent->GetShowDeMorgan() ) + { + m_Parent->SetShowDeMorgan( true ); + SetUnsetConvert(); + } + } + else + { + if( m_Parent->GetShowDeMorgan() ) + { + m_Parent->SetShowDeMorgan( false ); + SetUnsetConvert(); + } + } + + component->SetShowPinNumbers( m_ShowPinNumButt->GetValue() ); + component->SetShowPinNames( m_ShowPinNameButt->GetValue() ); + + if( m_PinsNameInsideButt->GetValue() == false ) + component->SetPinNameOffset( 0 ); // pin text outside the body (name is on the pin) + else + { + component->SetPinNameOffset( m_SetSkew->GetValue() ); + // Ensure component->m_TextInside != 0, because the meaning is "text outside". + if( component->GetPinNameOffset() == 0 ) + component->SetPinNameOffset( 20 ); // give a reasonnable value + } + + if( m_OptionPower->GetValue() == true ) + component->SetPower(); + else + component->SetNormal(); + + /* Set the option "Units locked". + * Obviously, cannot be true if there is only one part */ + component->LockUnits( m_OptionPartsLocked->GetValue() ); + + if( component->GetUnitCount() <= 1 ) + component->LockUnits( false ); + + /* Update the footprint filter list */ + component->GetFootPrints().Clear(); + component->GetFootPrints() = m_FootprintFilterListBox->GetStrings(); + + EndModal( wxID_OK ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::CopyDocFromRootToAlias( wxCommandEvent& event ) +{ + if( m_Parent == NULL ) + return; + + LIB_ALIAS* parent_alias; + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL ) + return; + + // search for the main alias: this is the first alias in alias list + // something like the main component + parent_alias = component->GetAlias( 0 ); + + if( parent_alias == NULL ) // Should never occur (bug) + return; + + m_DocCtrl->SetValue( parent_alias->GetDescription() ); + m_DocfileCtrl->SetValue( parent_alias->GetDocFileName() ); + m_KeywordsCtrl->SetValue( parent_alias->GetKeyWords() ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAllAliasOfPart( wxCommandEvent& event ) +{ + if( m_PartAliasListCtrl->FindString( m_Parent->GetAliasName() ) != wxNOT_FOUND ) + { + wxString msg; + msg.Printf( _( "Alias <%s> cannot be removed while it is being edited!" ), + GetChars( m_Parent->GetAliasName() ) ); + DisplayError( this, msg ); + return; + } + + if( IsOK( this, _( "Remove all aliases from list?" ) ) ) + { + m_PartAliasListCtrl->Clear(); + m_ButtonDeleteAllAlias->Enable( false ); + m_ButtonDeleteOneAlias->Enable( false ); + } +} + + +/* Add a new name to the alias list box + * New name cannot be the root name, and must not exists + */ +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::AddAliasOfPart( wxCommandEvent& event ) +{ + wxString aliasname; + LIB_PART* component = m_Parent->GetCurPart(); + PART_LIB* library = m_Parent->GetCurLib(); + + if( component == NULL ) + return; + + wxTextEntryDialog dlg( this, _( "New alias:" ), _( "Component Alias" ), aliasname ); + + if( dlg.ShowModal() != wxID_OK ) + return; // cancelled by user + + aliasname = dlg.GetValue( ); + + aliasname.Replace( wxT( " " ), wxT( "_" ) ); + if( aliasname.IsEmpty() ) + return; + + if( m_PartAliasListCtrl->FindString( aliasname ) != wxNOT_FOUND ) + { + wxString msg; + msg.Printf( _( "Alias or component name <%s> already in use." ), + GetChars( aliasname ) ); + DisplayError( this, msg ); + return; + } + + if( library && library->FindEntry( aliasname ) != NULL ) + { + wxString msg; + msg.Printf( _( "Alias or component name <%s> already exists in library <%s>." ), + GetChars( aliasname ), + GetChars( library->GetName() ) ); + DisplayError( this, msg ); + return; + } + + m_PartAliasListCtrl->Append( aliasname ); + + if( m_Parent->GetAliasName().CmpNoCase( component->GetName() ) == 0 ) + m_ButtonDeleteAllAlias->Enable( true ); + + m_ButtonDeleteOneAlias->Enable( true ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAliasOfPart( wxCommandEvent& event ) +{ + wxString aliasname = m_PartAliasListCtrl->GetStringSelection(); + + if( aliasname.IsEmpty() ) + return; + + if( aliasname.CmpNoCase( m_Parent->GetAliasName() ) == 0 ) + { + wxString msg; + msg.Printf( _( "Alias <%s> cannot be removed while it is being edited!" ), + GetChars( aliasname ) ); + DisplayError( this, msg ); + return; + } + + m_PartAliasListCtrl->Delete( m_PartAliasListCtrl->GetSelection() ); + LIB_PART* component = m_Parent->GetCurPart(); + + if( component ) + component->RemoveAlias( aliasname ); + + if( m_PartAliasListCtrl->IsEmpty() ) + { + m_ButtonDeleteAllAlias->Enable( false ); + m_ButtonDeleteOneAlias->Enable( false ); + } +} + + +/* + * Change the number of parts per package. + */ +bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::ChangeNbUnitsPerPackage( int MaxUnit ) +{ + LIB_PART* part = m_Parent->GetCurPart(); + + if( !part || part->GetUnitCount() == MaxUnit || MaxUnit < 1 ) + return false; + + if( MaxUnit < part->GetUnitCount() + && !IsOK( this, _( "Delete extra parts from component?" ) ) ) + return false; + + part->SetUnitCount( MaxUnit ); + return true; +} + + +/* + * Set or clear the component alternate body style ( DeMorgan ). + */ +bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::SetUnsetConvert() +{ + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL || ( m_Parent->GetShowDeMorgan() == component->HasConversion() ) ) + return false; + + if( m_Parent->GetShowDeMorgan() ) + { + if( !IsOK( this, _( "Add new pins for alternate body style ( DeMorgan ) to component?" ) ) ) + return false; + } + else if( component->HasConversion() ) + { + if( !IsOK( this, _( "Delete alternate body style (DeMorgan) draw items from component?" ) ) ) + { + m_Parent->SetShowDeMorgan( true ); + return false; + } + } + + component->SetConversion( m_Parent->GetShowDeMorgan() ); + m_Parent->OnModify(); + + return true; +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::BrowseAndSelectDocFile( wxCommandEvent& event ) +{ + PROJECT& prj = Prj(); + SEARCH_STACK* search = prj.SchSearchS(); + + wxString mask = wxT( "*" ); + wxString docpath = prj.GetRString( PROJECT::DOC_PATH ); + + if( !docpath ) + docpath = search->LastVisitedPath( wxT( "doc" ) ); + + wxString fullFileName = EDA_FILE_SELECTOR( _( "Doc Files" ), + docpath, + wxEmptyString, + wxEmptyString, + mask, + this, + wxFD_OPEN, + true ); + if( fullFileName.IsEmpty() ) + return; + + /* If the path is already in the library search paths + * list, just add the library name to the list. Otherwise, add + * the library name with the full or relative path. + * the relative path, when possible is preferable, + * because it preserve use of default libraries paths, when the path is a sub path of + * these default paths + */ + wxFileName fn = fullFileName; + + prj.SetRString( PROJECT::DOC_PATH, fn.GetPath() ); + + wxString filename = search->FilenameWithRelativePathInSearchList( + fullFileName, wxPathOnly( Prj().GetProjectFullName() ) ); + + // Filenames are always stored in unix like mode, ie separator "\" is stored as "/" + // to ensure files are identical under unices and windows +#ifdef __WINDOWS__ + filename.Replace( wxT( "\\" ), wxT( "/" ) ); +#endif + m_DocfileCtrl->SetValue( filename ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAllFootprintFilter( wxCommandEvent& event ) +{ + if( IsOK( this, _( "OK to delete the footprint filter list ?" ) ) ) + { + m_FootprintFilterListBox->Clear(); + m_ButtonDeleteAllFootprintFilter->Enable( false ); + m_ButtonDeleteOneFootprintFilter->Enable( false ); + m_buttonEditOneFootprintFilter->Enable( false ); + } +} + + +/* Add a new name to the footprint filter list box + * Obvioulsy, cannot be void + */ +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::AddFootprintFilter( wxCommandEvent& event ) +{ + wxString Line; + LIB_PART* component = m_Parent->GetCurPart(); + + if( component == NULL ) + return; + + wxTextEntryDialog dlg( this, _( "Add Footprint Filter" ), _( "Footprint Filter" ), Line ); + if( dlg.ShowModal() != wxID_OK ) + return; // cancelled by user + + Line = dlg.GetValue(); + Line.Replace( wxT( " " ), wxT( "_" ) ); + + if( Line.IsEmpty() ) + return; + + /* test for an existing name: */ + int index = m_FootprintFilterListBox->FindString( Line ); + + if( index != wxNOT_FOUND ) + { + wxString msg; + + msg.Printf( _( "Foot print filter <%s> is already defined." ), GetChars( Line ) ); + DisplayError( this, msg ); + return; + } + + m_FootprintFilterListBox->Append( Line ); + m_ButtonDeleteAllFootprintFilter->Enable( true ); + m_ButtonDeleteOneFootprintFilter->Enable( true ); + m_buttonEditOneFootprintFilter->Enable( true ); +} + + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteOneFootprintFilter( wxCommandEvent& event ) +{ + LIB_PART* component = m_Parent->GetCurPart(); + int ii = m_FootprintFilterListBox->GetSelection(); + + m_FootprintFilterListBox->Delete( ii ); + + if( !component || ( m_FootprintFilterListBox->GetCount() == 0 ) ) + { + m_ButtonDeleteAllFootprintFilter->Enable( false ); + m_ButtonDeleteOneFootprintFilter->Enable( false ); + m_buttonEditOneFootprintFilter->Enable( false ); + } +} + +void DIALOG_EDIT_COMPONENT_IN_LIBRARY::EditOneFootprintFilter( wxCommandEvent& event ) +{ + int idx = m_FootprintFilterListBox->GetSelection(); + + if( idx < 0 ) + return; + + wxString filter = m_FootprintFilterListBox->GetStringSelection(); + + wxTextEntryDialog dlg( this, wxEmptyString, _( "Edit footprint filter" ), filter ); + + if( dlg.ShowModal() != wxID_OK ) + return; // Aborted by user + + filter = dlg.GetValue(); + + if( filter.IsEmpty() ) + return; // do not accept blank filter. + + m_FootprintFilterListBox->SetString( idx, filter ); +} diff --git a/eeschema/dialogs/dialog_edit_component_in_lib.h b/eeschema/dialogs/dialog_edit_component_in_lib.h new file mode 100644 index 00000000..829a8cc4 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_lib.h @@ -0,0 +1,70 @@ +/** + * @file dialog_edit_component_in_lib.h + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 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_EDIT_COMPONENT_IN_LIB_H_ +#define _DIALOG_EDIT_COMPONENT_IN_LIB_H_ + +#include + + +class DIALOG_EDIT_COMPONENT_IN_LIBRARY: public DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE +{ + static int m_lastOpenedPage; // To remember the last notebook selection + +public: + LIB_EDIT_FRAME* m_Parent; + bool m_RecreateToolbar; + int m_AliasLocation; + +public: + /// Constructors + DIALOG_EDIT_COMPONENT_IN_LIBRARY( LIB_EDIT_FRAME* parent); + ~DIALOG_EDIT_COMPONENT_IN_LIBRARY(); + +private: + void initDlg(); + void InitPanelDoc(); + void InitBasicPanel(); + void OnCancelClick( wxCommandEvent& event ); + void OnOkClick(wxCommandEvent& event); + void DeleteAllAliasOfPart(wxCommandEvent& event); + void DeleteAliasOfPart(wxCommandEvent& event); + void AddAliasOfPart(wxCommandEvent& event); + bool ChangeNbUnitsPerPackage(int newUnit); + bool SetUnsetConvert(); + void CopyDocFromRootToAlias(wxCommandEvent& event); + void BrowseAndSelectDocFile(wxCommandEvent& event); + + void DeleteAllFootprintFilter(wxCommandEvent& event); + void DeleteOneFootprintFilter(wxCommandEvent& event); + void AddFootprintFilter(wxCommandEvent& event); + void EditOneFootprintFilter( wxCommandEvent& event ); +}; + +#endif + // _DIALOG_EDIT_COMPONENT_IN_LIB_H_ diff --git a/eeschema/dialogs/dialog_edit_component_in_lib_base.cpp b/eeschema/dialogs/dialog_edit_component_in_lib_base.cpp new file mode 100644 index 00000000..57f59d6d --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_lib_base.cpp @@ -0,0 +1,294 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_edit_component_in_lib_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DIALOG_EDIT_COMPONENT_IN_LIBRARY_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bUpperSizer; + bUpperSizer = new wxBoxSizer( wxVERTICAL ); + + m_NoteBook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0|wxTAB_TRAVERSAL ); + m_PanelBasic = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizerBasicPanel; + bSizerBasicPanel = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* m_OptionsBoxSizer; + m_OptionsBoxSizer = new wxStaticBoxSizer( new wxStaticBox( m_PanelBasic, wxID_ANY, _("General") ), wxVERTICAL ); + + m_AsConvertButt = new wxCheckBox( m_PanelBasic, wxID_ANY, _("Has alternate symbol (DeMorgan)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_AsConvertButt->SetToolTip( _("Check this option if the component has an alternate body style (De Morgan)") ); + + m_OptionsBoxSizer->Add( m_AsConvertButt, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_ShowPinNumButt = new wxCheckBox( m_PanelBasic, wxID_ANY, _("Show pin number"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ShowPinNumButt->SetValue(true); + m_ShowPinNumButt->SetToolTip( _("Show or hide pin numbers") ); + + m_OptionsBoxSizer->Add( m_ShowPinNumButt, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_ShowPinNameButt = new wxCheckBox( m_PanelBasic, wxID_ANY, _("Show pin name"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ShowPinNameButt->SetValue(true); + m_ShowPinNameButt->SetToolTip( _("Show or hide pin names") ); + + m_OptionsBoxSizer->Add( m_ShowPinNameButt, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_PinsNameInsideButt = new wxCheckBox( m_PanelBasic, wxID_ANY, _("Place pin names inside"), wxDefaultPosition, wxDefaultSize, 0 ); + m_PinsNameInsideButt->SetValue(true); + m_PinsNameInsideButt->SetToolTip( _("Check this option to have pin names inside the body and pin number outside.\nIf not checked pins names and pins numbers are outside.") ); + + m_OptionsBoxSizer->Add( m_PinsNameInsideButt, 0, wxALL, 5 ); + + + bSizerBasicPanel->Add( m_OptionsBoxSizer, 0, 0, 5 ); + + m_staticline3 = new wxStaticLine( m_PanelBasic, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerBasicPanel->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizerMidBasicPanel; + bSizerMidBasicPanel = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizernbunits; + bSizernbunits = new wxBoxSizer( wxVERTICAL ); + + m_staticTextNbUnits = new wxStaticText( m_PanelBasic, wxID_ANY, _("Number of Units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextNbUnits->Wrap( -1 ); + m_staticTextNbUnits->SetToolTip( _("Enter the number of units for a component that contains more than one unit") ); + + bSizernbunits->Add( m_staticTextNbUnits, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_SelNumberOfUnits = new wxSpinCtrl( m_PanelBasic, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 26, 1 ); + bSizernbunits->Add( m_SelNumberOfUnits, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + + bSizerMidBasicPanel->Add( bSizernbunits, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizerOffset; + bSizerOffset = new wxBoxSizer( wxVERTICAL ); + + m_staticTextskew = new wxStaticText( m_PanelBasic, wxID_ANY, _("Pin Name Position Offset"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextskew->Wrap( -1 ); + m_staticTextskew->SetToolTip( _("Margin (in 0.001 inches) between a pin name position and the component body.\nA value from 10 to 40 is usually good.") ); + + bSizerOffset->Add( m_staticTextskew, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_SetSkew = new wxSpinCtrl( m_PanelBasic, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 0 ); + bSizerOffset->Add( m_SetSkew, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizerMidBasicPanel->Add( bSizerOffset, 1, wxEXPAND, 5 ); + + + bSizerBasicPanel->Add( bSizerMidBasicPanel, 0, wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( m_PanelBasic, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerBasicPanel->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_OptionPower = new wxCheckBox( m_PanelBasic, wxID_ANY, _("Define as power symbol"), wxDefaultPosition, wxDefaultSize, 0 ); + m_OptionPower->SetToolTip( _("Check this option when the component is a power symbol") ); + + bSizerBasicPanel->Add( m_OptionPower, 0, wxALL, 5 ); + + m_OptionPartsLocked = new wxCheckBox( m_PanelBasic, wxID_ANY, _("All units are not interchangeable"), wxDefaultPosition, wxDefaultSize, 0 ); + m_OptionPartsLocked->SetToolTip( _("Check this option when creating multiple unit components and all units are not interchangeable") ); + + bSizerBasicPanel->Add( m_OptionPartsLocked, 0, wxALL, 5 ); + + + m_PanelBasic->SetSizer( bSizerBasicPanel ); + m_PanelBasic->Layout(); + bSizerBasicPanel->Fit( m_PanelBasic ); + m_NoteBook->AddPage( m_PanelBasic, _("Options"), true ); + m_PanelDoc = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* m_PanelDocBoxSizer; + m_PanelDocBoxSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticTextDescription = new wxStaticText( m_PanelDoc, wxID_ANY, _("Description"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDescription->Wrap( -1 ); + m_staticTextDescription->SetToolTip( _("A short description that is displayed in Eeschema.\nCan be a very good help when selecting components in libraries components lists.") ); + + m_PanelDocBoxSizer->Add( m_staticTextDescription, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_DocCtrl = new wxTextCtrl( m_PanelDoc, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_DocCtrl->SetMaxLength( 0 ); + m_PanelDocBoxSizer->Add( m_DocCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextKeywords = new wxStaticText( m_PanelDoc, wxID_ANY, _("Keywords"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextKeywords->Wrap( -1 ); + m_staticTextKeywords->SetToolTip( _("Enter key words that can be used to select this component.\nKey words cannot have spaces and are separated by a space.") ); + + m_PanelDocBoxSizer->Add( m_staticTextKeywords, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_KeywordsCtrl = new wxTextCtrl( m_PanelDoc, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_KeywordsCtrl->SetMaxLength( 0 ); + m_PanelDocBoxSizer->Add( m_KeywordsCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextDocFileName = new wxStaticText( m_PanelDoc, wxID_ANY, _("Documentation File Name"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDocFileName->Wrap( -1 ); + m_staticTextDocFileName->SetToolTip( _("Enter the documentation file (a .pdf document) associated to the component.") ); + + m_PanelDocBoxSizer->Add( m_staticTextDocFileName, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_DocfileCtrl = new wxTextCtrl( m_PanelDoc, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,-1 ), 0 ); + m_DocfileCtrl->SetMaxLength( 0 ); + m_PanelDocBoxSizer->Add( m_DocfileCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerPaneldocbutts; + bSizerPaneldocbutts = new wxBoxSizer( wxHORIZONTAL ); + + m_ButtonCopyDoc = new wxButton( m_PanelDoc, ID_COPY_DOC_TO_ALIAS, _("Copy Document from Parent"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerPaneldocbutts->Add( m_ButtonCopyDoc, 0, wxALL, 5 ); + + m_buttonBrowseDocFiles = new wxButton( m_PanelDoc, ID_BROWSE_DOC_FILES, _("Browse Files"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerPaneldocbutts->Add( m_buttonBrowseDocFiles, 0, wxALL, 5 ); + + + m_PanelDocBoxSizer->Add( bSizerPaneldocbutts, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + + m_PanelDoc->SetSizer( m_PanelDocBoxSizer ); + m_PanelDoc->Layout(); + m_PanelDocBoxSizer->Fit( m_PanelDoc ); + m_NoteBook->AddPage( m_PanelDoc, _("Description"), false ); + m_PanelAlias = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizerMainPanelAlias; + bSizerMainPanelAlias = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bLeftBoxSizerPanelAlias; + bLeftBoxSizerPanelAlias = new wxBoxSizer( wxVERTICAL ); + + m_staticTextAlias = new wxStaticText( m_PanelAlias, wxID_ANY, _("Alias List"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextAlias->Wrap( -1 ); + m_staticTextAlias->SetToolTip( _("An alias is a component that uses the body of its root component.\nIt has its own documentation and keywords.\nA fast way to extend a library with similar components") ); + + bLeftBoxSizerPanelAlias->Add( m_staticTextAlias, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_PartAliasListCtrl = new wxListBox( m_PanelAlias, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + bLeftBoxSizerPanelAlias->Add( m_PartAliasListCtrl, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizerMainPanelAlias->Add( bLeftBoxSizerPanelAlias, 1, wxEXPAND, 5 ); + + wxBoxSizer* bRightBoxSizerPanelAlias; + bRightBoxSizerPanelAlias = new wxBoxSizer( wxVERTICAL ); + + m_ButtonAddeAlias = new wxButton( m_PanelAlias, ID_ADD_ALIAS, _("Add"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightBoxSizerPanelAlias->Add( m_ButtonAddeAlias, 0, wxALL|wxEXPAND, 5 ); + + m_ButtonDeleteOneAlias = new wxButton( m_PanelAlias, ID_DELETE_ONE_ALIAS, _("Delete"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightBoxSizerPanelAlias->Add( m_ButtonDeleteOneAlias, 0, wxALL|wxEXPAND, 5 ); + + m_ButtonDeleteAllAlias = new wxButton( m_PanelAlias, ID_DELETE_ALL_ALIAS, _("Delete All"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightBoxSizerPanelAlias->Add( m_ButtonDeleteAllAlias, 0, wxALL, 5 ); + + + bSizerMainPanelAlias->Add( bRightBoxSizerPanelAlias, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + m_PanelAlias->SetSizer( bSizerMainPanelAlias ); + m_PanelAlias->Layout(); + bSizerMainPanelAlias->Fit( m_PanelAlias ); + m_NoteBook->AddPage( m_PanelAlias, _("Alias"), false ); + m_PanelFootprintFilter = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bPanelFpFilterBoxSizer; + bPanelFpFilterBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bFpFilterLeftBoxSizer; + bFpFilterLeftBoxSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticTextFootprints = new wxStaticText( m_PanelFootprintFilter, wxID_ANY, _("Footprints"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextFootprints->Wrap( -1 ); + m_staticTextFootprints->SetToolTip( _("A list of footprints names that can be used for this component.\nFootprints names can used jockers.\n(like sm* to allow all footprints names starting by sm).") ); + + bFpFilterLeftBoxSizer->Add( m_staticTextFootprints, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_FootprintFilterListBox = new wxListBox( m_PanelFootprintFilter, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + bFpFilterLeftBoxSizer->Add( m_FootprintFilterListBox, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bPanelFpFilterBoxSizer->Add( bFpFilterLeftBoxSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bFpFilterRightBoxSizer; + bFpFilterRightBoxSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonAddFpF = new wxButton( m_PanelFootprintFilter, ID_ADD_FOOTPRINT_FILTER, _("Add"), wxDefaultPosition, wxDefaultSize, 0 ); + bFpFilterRightBoxSizer->Add( m_buttonAddFpF, 0, wxALL|wxEXPAND, 5 ); + + m_buttonEditOneFootprintFilter = new wxButton( m_PanelFootprintFilter, wxID_ANY, _("Edit"), wxDefaultPosition, wxDefaultSize, 0 ); + bFpFilterRightBoxSizer->Add( m_buttonEditOneFootprintFilter, 0, wxALL|wxEXPAND, 5 ); + + m_ButtonDeleteOneFootprintFilter = new wxButton( m_PanelFootprintFilter, ID_DELETE_ONE_FOOTPRINT_FILTER, _("Delete"), wxDefaultPosition, wxDefaultSize, 0 ); + bFpFilterRightBoxSizer->Add( m_ButtonDeleteOneFootprintFilter, 0, wxALL|wxEXPAND, 5 ); + + m_ButtonDeleteAllFootprintFilter = new wxButton( m_PanelFootprintFilter, ID_DELETE_ALL_FOOTPRINT_FILTER, _("Delete All"), wxDefaultPosition, wxDefaultSize, 0 ); + bFpFilterRightBoxSizer->Add( m_ButtonDeleteAllFootprintFilter, 0, wxALL|wxEXPAND, 5 ); + + + bPanelFpFilterBoxSizer->Add( bFpFilterRightBoxSizer, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + m_PanelFootprintFilter->SetSizer( bPanelFpFilterBoxSizer ); + m_PanelFootprintFilter->Layout(); + bPanelFpFilterBoxSizer->Fit( m_PanelFootprintFilter ); + m_NoteBook->AddPage( m_PanelFootprintFilter, _("Footprint Filter"), false ); + + bUpperSizer->Add( m_NoteBook, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bUpperSizer, 1, wxEXPAND, 5 ); + + m_stdSizerButton = new wxStdDialogButtonSizer(); + m_stdSizerButtonOK = new wxButton( this, wxID_OK ); + m_stdSizerButton->AddButton( m_stdSizerButtonOK ); + m_stdSizerButtonCancel = new wxButton( this, wxID_CANCEL ); + m_stdSizerButton->AddButton( m_stdSizerButtonCancel ); + m_stdSizerButton->Realize(); + + bMainSizer->Add( m_stdSizerButton, 0, wxEXPAND|wxALL, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + // Connect Events + m_ButtonCopyDoc->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::CopyDocFromRootToAlias ), NULL, this ); + m_buttonBrowseDocFiles->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::BrowseAndSelectDocFile ), NULL, this ); + m_ButtonAddeAlias->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::AddAliasOfPart ), NULL, this ); + m_ButtonDeleteOneAlias->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAliasOfPart ), NULL, this ); + m_ButtonDeleteAllAlias->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAllAliasOfPart ), NULL, this ); + m_buttonAddFpF->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::AddFootprintFilter ), NULL, this ); + m_buttonEditOneFootprintFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::EditOneFootprintFilter ), NULL, this ); + m_ButtonDeleteOneFootprintFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteOneFootprintFilter ), NULL, this ); + m_ButtonDeleteAllFootprintFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAllFootprintFilter ), NULL, this ); + m_stdSizerButtonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::OnCancelClick ), NULL, this ); + m_stdSizerButtonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::~DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE() +{ + // Disconnect Events + m_ButtonCopyDoc->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::CopyDocFromRootToAlias ), NULL, this ); + m_buttonBrowseDocFiles->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::BrowseAndSelectDocFile ), NULL, this ); + m_ButtonAddeAlias->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::AddAliasOfPart ), NULL, this ); + m_ButtonDeleteOneAlias->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAliasOfPart ), NULL, this ); + m_ButtonDeleteAllAlias->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAllAliasOfPart ), NULL, this ); + m_buttonAddFpF->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::AddFootprintFilter ), NULL, this ); + m_buttonEditOneFootprintFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::EditOneFootprintFilter ), NULL, this ); + m_ButtonDeleteOneFootprintFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteOneFootprintFilter ), NULL, this ); + m_ButtonDeleteAllFootprintFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::DeleteAllFootprintFilter ), NULL, this ); + m_stdSizerButtonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::OnCancelClick ), NULL, this ); + m_stdSizerButtonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE::OnOkClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_edit_component_in_lib_base.fbp b/eeschema/dialogs/dialog_edit_component_in_lib_base.fbp new file mode 100644 index 00000000..92539715 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_lib_base.fbp @@ -0,0 +1,3354 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_edit_component_in_lib_base + 1000 + none + 1 + DIALOG_EDIT_COMPONENT_IN_LIBRARY_FBP + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + ID_LIBEDIT_NOTEBOOK + + + DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Library Component Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bUpperSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_NoteBook + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + Options + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelBasic + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerBasicPanel + wxVERTICAL + none + + 5 + + 0 + + wxID_ANY + General + + m_OptionsBoxSizer + wxVERTICAL + none + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Has alternate symbol (DeMorgan) + + 0 + + + 0 + + 1 + m_AsConvertButt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check this option if the component has an alternate body style (De Morgan) + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show pin number + + 0 + + + 0 + + 1 + m_ShowPinNumButt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Show or hide pin numbers + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show pin name + + 0 + + + 0 + + 1 + m_ShowPinNameButt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Show or hide pin names + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Place pin names inside + + 0 + + + 0 + + 1 + m_PinsNameInsideButt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check this option to have pin names inside the body and pin number outside. If not checked pins names and pins numbers are outside. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline3 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizerMidBasicPanel + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizernbunits + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Number of Units + + 0 + + + 0 + + 1 + m_staticTextNbUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Enter the number of units for a component that contains more than one unit + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 1 + 26 + + 0 + + 1 + + 0 + + 1 + m_SelNumberOfUnits + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerOffset + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pin Name Position Offset + + 0 + + + 0 + + 1 + m_staticTextskew + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Margin (in 0.001 inches) between a pin name position and the component body. A value from 10 to 40 is usually good. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 100 + + 0 + + 1 + + 0 + + 1 + m_SetSkew + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Define as power symbol + + 0 + + + 0 + + 1 + m_OptionPower + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check this option when the component is a power symbol + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + All units are not interchangeable + + 0 + + + 0 + + 1 + m_OptionPartsLocked + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check this option when creating multiple unit components and all units are not interchangeable + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Description + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelDoc + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + m_PanelDocBoxSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Description + + 0 + + + 0 + + 1 + m_staticTextDescription + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + A short description that is displayed in Eeschema. Can be a very good help when selecting components in libraries components lists. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_DocCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Keywords + + 0 + + + 0 + + 1 + m_staticTextKeywords + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Enter key words that can be used to select this component. Key words cannot have spaces and are separated by a space. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_KeywordsCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Documentation File Name + + 0 + + + 0 + + 1 + m_staticTextDocFileName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Enter the documentation file (a .pdf document) associated to the component. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_DocfileCtrl + 1 + + + protected + 1 + + Resizable + 1 + 400,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_HORIZONTAL + 0 + + + bSizerPaneldocbutts + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_COPY_DOC_TO_ALIAS + Copy Document from Parent + + 0 + + + 0 + + 1 + m_ButtonCopyDoc + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + CopyDocFromRootToAlias + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_BROWSE_DOC_FILES + Browse Files + + 0 + + + 0 + + 1 + m_buttonBrowseDocFiles + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + BrowseAndSelectDocFile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alias + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelAlias + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMainPanelAlias + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bLeftBoxSizerPanelAlias + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Alias List + + 0 + + + 0 + + 1 + m_staticTextAlias + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + An alias is a component that uses the body of its root component. It has its own documentation and keywords. A fast way to extend a library with similar components + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PartAliasListCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + bRightBoxSizerPanelAlias + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ADD_ALIAS + Add + + 0 + + + 0 + + 1 + m_ButtonAddeAlias + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + AddAliasOfPart + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_DELETE_ONE_ALIAS + Delete + + 0 + + + 0 + + 1 + m_ButtonDeleteOneAlias + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + DeleteAliasOfPart + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_DELETE_ALL_ALIAS + Delete All + + 0 + + + 0 + + 1 + m_ButtonDeleteAllAlias + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + DeleteAllAliasOfPart + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Footprint Filter + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelFootprintFilter + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bPanelFpFilterBoxSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bFpFilterLeftBoxSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Footprints + + 0 + + + 0 + + 1 + m_staticTextFootprints + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + A list of footprints names that can be used for this component. Footprints names can used jockers. (like sm* to allow all footprints names starting by sm). + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_FootprintFilterListBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + bFpFilterRightBoxSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ADD_FOOTPRINT_FILTER + Add + + 0 + + + 0 + + 1 + m_buttonAddFpF + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + AddFootprintFilter + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Edit + + 0 + + + 0 + + 1 + m_buttonEditOneFootprintFilter + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + EditOneFootprintFilter + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_DELETE_ONE_FOOTPRINT_FILTER + Delete + + 0 + + + 0 + + 1 + m_ButtonDeleteOneFootprintFilter + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + DeleteOneFootprintFilter + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_DELETE_ALL_FOOTPRINT_FILTER + Delete All + + 0 + + + 0 + + 1 + m_ButtonDeleteAllFootprintFilter + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + DeleteAllFootprintFilter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdSizerButton + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_edit_component_in_lib_base.h b/eeschema/dialogs/dialog_edit_component_in_lib_base.h new file mode 100644 index 00000000..2dc78d79 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_lib_base.h @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EDIT_COMPONENT_IN_LIB_BASE_H__ +#define __DIALOG_EDIT_COMPONENT_IN_LIB_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define ID_LIBEDIT_NOTEBOOK 1000 +#define ID_COPY_DOC_TO_ALIAS 1001 +#define ID_BROWSE_DOC_FILES 1002 +#define ID_ADD_ALIAS 1003 +#define ID_DELETE_ONE_ALIAS 1004 +#define ID_DELETE_ALL_ALIAS 1005 +#define ID_ADD_FOOTPRINT_FILTER 1006 +#define ID_DELETE_ONE_FOOTPRINT_FILTER 1007 +#define ID_DELETE_ALL_FOOTPRINT_FILTER 1008 + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxNotebook* m_NoteBook; + wxPanel* m_PanelBasic; + wxCheckBox* m_AsConvertButt; + wxCheckBox* m_ShowPinNumButt; + wxCheckBox* m_ShowPinNameButt; + wxCheckBox* m_PinsNameInsideButt; + wxStaticLine* m_staticline3; + wxStaticText* m_staticTextNbUnits; + wxSpinCtrl* m_SelNumberOfUnits; + wxStaticText* m_staticTextskew; + wxSpinCtrl* m_SetSkew; + wxStaticLine* m_staticline1; + wxCheckBox* m_OptionPower; + wxCheckBox* m_OptionPartsLocked; + wxPanel* m_PanelDoc; + wxStaticText* m_staticTextDescription; + wxTextCtrl* m_DocCtrl; + wxStaticText* m_staticTextKeywords; + wxTextCtrl* m_KeywordsCtrl; + wxStaticText* m_staticTextDocFileName; + wxTextCtrl* m_DocfileCtrl; + wxButton* m_ButtonCopyDoc; + wxButton* m_buttonBrowseDocFiles; + wxPanel* m_PanelAlias; + wxStaticText* m_staticTextAlias; + wxListBox* m_PartAliasListCtrl; + wxButton* m_ButtonAddeAlias; + wxButton* m_ButtonDeleteOneAlias; + wxButton* m_ButtonDeleteAllAlias; + wxPanel* m_PanelFootprintFilter; + wxStaticText* m_staticTextFootprints; + wxListBox* m_FootprintFilterListBox; + wxButton* m_buttonAddFpF; + wxButton* m_buttonEditOneFootprintFilter; + wxButton* m_ButtonDeleteOneFootprintFilter; + wxButton* m_ButtonDeleteAllFootprintFilter; + wxStdDialogButtonSizer* m_stdSizerButton; + wxButton* m_stdSizerButtonOK; + wxButton* m_stdSizerButtonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void CopyDocFromRootToAlias( wxCommandEvent& event ) { event.Skip(); } + virtual void BrowseAndSelectDocFile( wxCommandEvent& event ) { event.Skip(); } + virtual void AddAliasOfPart( wxCommandEvent& event ) { event.Skip(); } + virtual void DeleteAliasOfPart( wxCommandEvent& event ) { event.Skip(); } + virtual void DeleteAllAliasOfPart( wxCommandEvent& event ) { event.Skip(); } + virtual void AddFootprintFilter( wxCommandEvent& event ) { event.Skip(); } + virtual void EditOneFootprintFilter( wxCommandEvent& event ) { event.Skip(); } + virtual void DeleteOneFootprintFilter( wxCommandEvent& event ) { event.Skip(); } + virtual void DeleteAllFootprintFilter( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE( wxWindow* parent, wxWindowID id = ID_LIBEDIT_NOTEBOOK, const wxString& title = _("Library Component Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE(); + +}; + +#endif //__DIALOG_EDIT_COMPONENT_IN_LIB_BASE_H__ diff --git a/eeschema/dialogs/dialog_edit_component_in_schematic.cpp b/eeschema/dialogs/dialog_edit_component_in_schematic.cpp new file mode 100644 index 00000000..105d6a51 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_schematic.cpp @@ -0,0 +1,1107 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 + */ + +/** + * @file dialog_edit_component_in_schematic.cpp + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +/** + * class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC + * is hand coded and implements DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP which + * is maintained by wxFormBuilder. Do not auto-generate this class or file, + * it is hand coded. + */ +class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC : public DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP +{ +public: + /** Constructor */ + DIALOG_EDIT_COMPONENT_IN_SCHEMATIC( wxWindow* aParent ); + + /** + * Function InitBuffers + * sets up to edit the given component. + * @param aComponent The component to edit. + */ + void InitBuffers( SCH_COMPONENT* aComponent ); + +private: + + friend class SCH_EDIT_FRAME; + + SCH_EDIT_FRAME* m_parent; + SCH_COMPONENT* m_cmp; + LIB_PART* m_part; + bool m_skipCopyFromPanel; + + static int s_SelectedRow; + + /// a copy of the edited component's SCH_FIELDs + SCH_FIELDS m_FieldsBuf; + + void setSelectedFieldNdx( int aFieldNdx ); + + int getSelectedFieldNdx(); + + /** + * Function copySelectedFieldToPanel + * sets the values displayed on the panel according to + * the currently selected field row + */ + void copySelectedFieldToPanel(); + + + /** + * Function copyPanelToSelectedField + * copies the values displayed on the panel fields to the currently + * selected field + * @return bool - true if all fields are OK, else false if the user has put + * bad data into a field, and this value can be used to deny a row change. + */ + bool copyPanelToSelectedField(); + + void copyOptionsToPanel(); + + void copyPanelToOptions(); + + void setRowItem( int aFieldNdx, const wxString& aName, const wxString& aValue ); + + void setRowItem( int aFieldNdx, const SCH_FIELD& aField ) + { + setRowItem( aFieldNdx, aField.GetName( false ), aField.GetText() ); + } + + // event handlers + void OnCloseDialog( wxCloseEvent& event ); + void OnListItemDeselected( wxListEvent& event ); + void OnListItemSelected( wxListEvent& event ); + void OnCancelButtonClick( wxCommandEvent& event ); + void OnOKButtonClick( wxCommandEvent& event ); + void SetInitCmp( wxCommandEvent& event ); + void addFieldButtonHandler( wxCommandEvent& event ); + void deleteFieldButtonHandler( wxCommandEvent& event ); + void moveUpButtonHandler( wxCommandEvent& event ); + void showButtonHandler( wxCommandEvent& event ); + void OnTestChipName( wxCommandEvent& event ); + void OnSelectChipName( wxCommandEvent& event ); + void OnInitDlg( wxInitDialogEvent& event ) + { + TransferDataToWindow(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); + } + + SCH_FIELD* findField( const wxString& aFieldName ); + + /** + * Function updateDisplay + * update the listbox showing fields, according to the fields texts + * must be called after a text change in fields, if this change is not an edition + */ + void updateDisplay( ) + { + for( unsigned ii = FIELD1; iiType() == SCH_COMPONENT_T, + wxT( "Invalid component object pointer. Bad Programmer!" ) ); + + m_canvas->SetIgnoreMouseEvents( true ); + + DIALOG_EDIT_COMPONENT_IN_SCHEMATIC* dlg = new DIALOG_EDIT_COMPONENT_IN_SCHEMATIC( this ); + + dlg->InitBuffers( aComponent ); + + // make sure the chipnameTextCtrl is wide enough to hold any unusually long chip names: + EnsureTextCtrlWidth( dlg->chipnameTextCtrl ); + + // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal + // frame. Therefore this dialog as a modal frame parent, MUST be run under + // quasimodal mode for the quasimodal frame support to work. So don't use + // the QUASIMODAL macros here. + int ret = dlg->ShowQuasiModal(); + + m_canvas->SetIgnoreMouseEvents( false ); + m_canvas->MoveCursorToCrossHair(); + dlg->Destroy(); + + if( ret == wxID_OK ) + GetCanvas()->Refresh(); +} + + +DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::DIALOG_EDIT_COMPONENT_IN_SCHEMATIC( wxWindow* aParent ) : + DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP( aParent ) +{ + m_parent = (SCH_EDIT_FRAME*) aParent; + + m_cmp = NULL; + m_part = NULL; + m_skipCopyFromPanel = false; + + wxListItem columnLabel; + + columnLabel.SetImage( -1 ); + + columnLabel.SetText( _( "Name" ) ); + fieldListCtrl->InsertColumn( 0, columnLabel ); + + columnLabel.SetText( _( "Value" ) ); + fieldListCtrl->InsertColumn( 1, columnLabel ); + + m_staticTextUnitSize->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + m_staticTextUnitPosX->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + m_staticTextUnitPosY->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + + wxToolTip::Enable( true ); + stdDialogButtonSizerOK->SetDefault(); + + FixOSXCancelButtonIssue(); + + Fit(); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemDeselected( wxListEvent& event ) +{ + if( !m_skipCopyFromPanel ) + { + if( !copyPanelToSelectedField() ) + event.Skip(); // do not go to the next row + } +} + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnTestChipName( wxCommandEvent& event ) +{ + wxString partname = chipnameTextCtrl->GetValue(); + LIB_PART* entry = Prj().SchLibs()->FindLibPart( partname ); + + wxString msg; + + if( entry ) + { + msg.Printf( _( "Component '%s' found in library '%s'" ), + GetChars( partname ), GetChars( entry->GetLibraryName() ) ); + wxMessageBox( msg ); + return; + } + + msg.Printf( _( "Component '%s' not found in any library" ), GetChars( partname ) ); + + // Try to find components which have a name "near" the current chip name, + // i.e. the same name when the comparison is case insensitive. + // Could be helpful for old designs when lower cases and upper case were + // equivalent. + std::vector candidates; + Prj().SchLibs()->FindLibraryNearEntries( candidates, partname ); + + if( candidates.size() == 0 ) + { + wxMessageBox( msg ); + return; + } + + // Some candidates are found. Show them: + msg << wxT("\n") << _( "However, some candidates are found:" ); + + // add candidate names: + for( unsigned ii = 0; ii < candidates.size(); ii++ ) + { + msg << wxT("\n") << + wxString::Format( _( "'%s' found in library '%s'" ), + GetChars( candidates[ii]->GetName() ), + GetChars( candidates[ii]->GetLibraryName() ) ); + } + + wxMessageBox( msg ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnSelectChipName( wxCommandEvent& event ) +{ + wxArrayString dummy; + int dummyunit = 1; + wxString chipname = m_parent->SelectComponentFromLibrary( NULL, dummy, dummyunit, + true, NULL, NULL ); + if( chipname.IsEmpty() ) + return; + + chipnameTextCtrl->SetValue( chipname ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemSelected( wxListEvent& event ) +{ + DBG( printf( "OnListItemSelected()\n" ); ) + + // remember the selected row, statically + s_SelectedRow = event.GetIndex(); + + copySelectedFieldToPanel(); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnCloseDialog( wxCloseEvent& event ) +{ + // On wxWidgets 2.8, and on Linux, calling EndQuasiModal here is mandatory + // Otherwise, the main event loop is never restored, and Eeschema does not + // respond to any event, because the DIALOG_SHIM destructor is never called. + // On wxWidgets 3.0, or on Windows, the DIALOG_SHIM destructor is called, + // and calls EndQuasiModal. + // therefore calling EndQuasiModal here is not always mandatory but it creates no issues + EndQuasiModal( wxID_CANCEL ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnCancelButtonClick( wxCommandEvent& event ) +{ + EndQuasiModal( wxID_CANCEL ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyPanelToOptions() +{ + wxString newname = chipnameTextCtrl->GetValue(); + + // Save current flags which could be modified by next change settings + STATUS_FLAGS flags = m_cmp->GetFlags(); + + newname.Replace( wxT( " " ), wxT( "_" ) ); + + if( newname.IsEmpty() ) + { + DisplayError( NULL, _( "No Component Name!" ) ); + } + else if( Cmp_KEEPCASE( newname, m_cmp->m_part_name ) ) + { + PART_LIBS* libs = Prj().SchLibs(); + + if( libs->FindLibraryEntry( newname ) == NULL ) + { + wxString msg = wxString::Format( _( + "Component '%s' not found!" ), GetChars( newname ) ); + DisplayError( this, msg ); + } + else // Change component from lib! + { + m_cmp->SetPartName( newname, libs ); + } + } + + // For components with multiple shapes (De Morgan representation) Set the selected shape: + if( convertCheckBox->IsEnabled() ) + { + m_cmp->SetConvert( convertCheckBox->GetValue() ? 2 : 1 ); + } + + //Set the part selection in multiple part per package + if( m_cmp->GetUnit() ) + { + int unit_selection = unitChoice->GetCurrentSelection() + 1; + + m_cmp->SetUnitSelection( &m_parent->GetCurrentSheet(), unit_selection ); + m_cmp->SetUnit( unit_selection ); + } + + switch( orientationRadioBox->GetSelection() ) + { + case 0: + m_cmp->SetOrientation( CMP_ORIENT_0 ); + break; + + case 1: + m_cmp->SetOrientation( CMP_ORIENT_90 ); + break; + + case 2: + m_cmp->SetOrientation( CMP_ORIENT_180 ); + break; + + case 3: + m_cmp->SetOrientation( CMP_ORIENT_270 ); + break; + } + + int mirror = mirrorRadioBox->GetSelection(); + + switch( mirror ) + { + case 0: + break; + + case 1: + m_cmp->SetOrientation( CMP_MIRROR_X ); + break; + + case 2: + m_cmp->SetOrientation( CMP_MIRROR_Y ); + break; + } + + // Restore m_Flag modified by SetUnit() and other change settings + m_cmp->ClearFlags(); + m_cmp->SetFlags( flags ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnOKButtonClick( wxCommandEvent& event ) +{ + bool removeRemainingFields = false; + + if( !copyPanelToSelectedField() ) + return; + + if( ! SCH_COMPONENT::IsReferenceStringValid( m_FieldsBuf[REFERENCE].GetText() ) ) + { + DisplayError( NULL, _( "Illegal reference. A reference must start with a letter" ) ); + return; + } + + // save old cmp in undo list if not already in edit, or moving ... + // or the component to be edited is part of a block + if( m_cmp->m_Flags == 0 + || m_parent->GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + m_parent->SaveCopyInUndoList( m_cmp, UR_CHANGED ); + + copyPanelToOptions(); + + // Delete any fields with no name before we copy all of m_FieldsBuf back into the component. + for( unsigned i = MANDATORY_FIELDS; iGetTemplates().HasFieldName( m_FieldsBuf[i].GetName( false ) ) + && !removeRemainingFields ) + { + wxString msg = wxString::Format( + _( "The field name <%s> does not have a value and is not defined in " + "the field template list. Empty field values are invalid an will " + "be removed from the component. Do you wish to remove this and " + "all remaining undefined fields?" ), + GetChars( m_FieldsBuf[i].GetName( false ) ) + ); + + wxMessageDialog dlg( this, msg, _( "Remove Fields" ), wxYES_NO | wxNO_DEFAULT ); + + if( dlg.ShowModal() == wxID_NO ) + return; + + removeRemainingFields = true; + } + + m_FieldsBuf.erase( m_FieldsBuf.begin() + i ); + continue; + } + + ++i; + } + + // change all field positions from relative to absolute + for( unsigned i = 0; im_Pos ); + } + + LIB_PART* entry = Prj().SchLibs()->FindLibPart( m_cmp->m_part_name ); + + if( entry && entry->IsPower() ) + m_FieldsBuf[VALUE].SetText( m_cmp->m_part_name ); + + // copy all the fields back, and change the length of m_Fields. + m_cmp->SetFields( m_FieldsBuf ); + + // Reference has a specific initialization, depending on the current active sheet + // because for a given component, in a complex hierarchy, there are more than one + // reference. + m_cmp->SetRef( &m_parent->GetCurrentSheet(), m_FieldsBuf[REFERENCE].GetText() ); + + m_parent->OnModify(); + m_parent->GetScreen()->TestDanglingEnds(); + + EndQuasiModal( wxID_OK ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::addFieldButtonHandler( wxCommandEvent& event ) +{ + // in case m_FieldsBuf[REFERENCE].m_Orient has changed on screen only, grab + // screen contents. + if( !copyPanelToSelectedField() ) + return; + + unsigned fieldNdx = m_FieldsBuf.size(); + + SCH_FIELD blank( wxPoint(), fieldNdx, m_cmp ); + + blank.SetOrientation( m_FieldsBuf[REFERENCE].GetOrientation() ); + + m_FieldsBuf.push_back( blank ); + m_FieldsBuf[fieldNdx].SetName( TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldNdx ) ); + + m_skipCopyFromPanel = true; + setRowItem( fieldNdx, m_FieldsBuf[fieldNdx] ); + + setSelectedFieldNdx( fieldNdx ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::deleteFieldButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + if( fieldNdx < MANDATORY_FIELDS ) + { + wxBell(); + return; + } + + m_skipCopyFromPanel = true; + m_FieldsBuf.erase( m_FieldsBuf.begin() + fieldNdx ); + fieldListCtrl->DeleteItem( fieldNdx ); + + if( fieldNdx >= m_FieldsBuf.size() ) + --fieldNdx; + + updateDisplay(); + + setSelectedFieldNdx( fieldNdx ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::showButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx == DATASHEET ) + { + wxString datasheet_uri = fieldValueTextCtrl->GetValue(); + ::wxLaunchDefaultBrowser( datasheet_uri ); + } + else if( fieldNdx == FOOTPRINT ) + { + // pick a footprint using the footprint picker. + wxString fpid; + + KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true ); + + if( frame->ShowModal( &fpid, this ) ) + { + // DBG( printf( "%s: %s\n", __func__, TO_UTF8( fpid ) ); ) + fieldValueTextCtrl->SetValue( fpid ); + + setRowItem( fieldNdx, m_FieldsBuf[fieldNdx].GetName( false ), fpid ); + } + + frame->Destroy(); + } +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::moveUpButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + if( fieldNdx <= MANDATORY_FIELDS ) + { + wxBell(); + return; + } + + if( !copyPanelToSelectedField() ) + return; + + // swap the fieldNdx field with the one before it, in both the vector + // and in the fieldListCtrl + SCH_FIELD tmp = m_FieldsBuf[fieldNdx - 1]; + + DBG( printf( "tmp.m_Text=\"%s\" tmp.m_Name=\"%s\"\n", + TO_UTF8( tmp.GetText() ), TO_UTF8( tmp.GetName( false ) ) ); ) + + m_FieldsBuf[fieldNdx - 1] = m_FieldsBuf[fieldNdx]; + setRowItem( fieldNdx - 1, m_FieldsBuf[fieldNdx] ); + + m_FieldsBuf[fieldNdx] = tmp; + setRowItem( fieldNdx, tmp ); + + updateDisplay(); + + m_skipCopyFromPanel = true; + setSelectedFieldNdx( fieldNdx - 1 ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::setSelectedFieldNdx( int aFieldNdx ) +{ + /* deselect old selection, but I think this is done by single selection + * flag within fieldListCtrl. + * fieldListCtrl->SetItemState( s_SelectedRow, 0, + * wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); + */ + + if( aFieldNdx >= (int) m_FieldsBuf.size() ) + aFieldNdx = m_FieldsBuf.size() - 1; + + if( aFieldNdx < 0 ) + aFieldNdx = 0; + + fieldListCtrl->SetItemState( aFieldNdx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + fieldListCtrl->EnsureVisible( aFieldNdx ); + + s_SelectedRow = aFieldNdx; +} + + +int DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::getSelectedFieldNdx() +{ + return s_SelectedRow; +} + + +SCH_FIELD* DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::findField( const wxString& aFieldName ) +{ + for( unsigned i=0; iFindLibPart( m_cmp->m_part_name ); + +#if 0 && defined(DEBUG) + for( int i = 0; iGetFieldCount(); ++i ) + { + printf( "Orig[%d] (x=%d, y=%d)\n", i, aComponent->m_Fields[i].GetTextPosition().x, + aComponent->m_Fields[i].GetTextPosition().y ); + } + +#endif + + // When this code was written, all field constructors ensure that the fixed fields + // are all present within a component. So we can knowingly copy them over + // in the normal order. Copy only the fixed fields at first. + // Please do not break the field constructors. + + m_FieldsBuf.clear(); + + for( int i=0; im_Fields[i] ); + + // make the editable field position relative to the component + m_FieldsBuf[i].SetTextPosition( m_FieldsBuf[i].GetTextPosition() - m_cmp->m_Pos ); + } + + // Add template fieldnames: + // Now copy in the template fields, in the order that they are present in the + // template field editor UI. + const TEMPLATE_FIELDNAMES& tfnames = m_parent->GetTemplateFieldNames(); + + for( TEMPLATE_FIELDNAMES::const_iterator it = tfnames.begin(); it!=tfnames.end(); ++it ) + { + // add a new field unconditionally to the UI only + SCH_FIELD fld( wxPoint(0,0), -1 /* id is a relic */, m_cmp, it->m_Name ); + + // See if field by same name already exists in component. + SCH_FIELD* schField = aComponent->FindField( it->m_Name ); + + // If the field does not already exist in the component, then we + // use defaults from the template fieldname, otherwise the original + // values from the component will be set. + if( !schField ) + { + if( !it->m_Visible ) + fld.SetVisible( false ); + else + fld.SetVisible( true ); + + fld.SetText( it->m_Value ); // empty? ok too. + } + else + { + fld = *schField; + + // make the editable field position relative to the component + fld.SetTextPosition( fld.GetTextPosition() - m_cmp->m_Pos ); + } + + m_FieldsBuf.push_back( fld ); + } + + // Lastly, append any original fields from the component which were not added + // from the set of fixed fields nor from the set of template fields. + for( unsigned i=MANDATORY_FIELDS; im_Fields.size(); ++i ) + { + SCH_FIELD* cmp = &aComponent->m_Fields[i]; + SCH_FIELD* buf = findField( cmp->GetName( false ) ); + + if( !buf ) + { + int newNdx = m_FieldsBuf.size(); + m_FieldsBuf.push_back( *cmp ); + + // make the editable field position relative to the component + m_FieldsBuf[newNdx].SetTextPosition( m_FieldsBuf[newNdx].GetTextPosition() - + m_cmp->m_Pos ); + } + } + + +#if 0 && defined(DEBUG) + for( unsigned i = 0; iGetRef( &m_parent->GetCurrentSheet() ) ); + + for( unsigned i = 0; iIsDragging() ) + { + orientationRadioBox->Disable(); + mirrorRadioBox->Disable(); + chipnameTextCtrl->Disable(); + } + + // put focus on the list ctrl + fieldListCtrl->SetFocus(); + + // resume editing at the last row edited, last time dialog was up. + setSelectedFieldNdx( s_SelectedRow ); + + copySelectedFieldToPanel(); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::setRowItem( int aFieldNdx, const wxString& aName, const wxString& aValue ) +{ + wxASSERT( aFieldNdx >= 0 ); + + // insert blanks if aFieldNdx is referencing a "yet to be defined" row + while( aFieldNdx >= fieldListCtrl->GetItemCount() ) + { + long ndx = fieldListCtrl->InsertItem( fieldListCtrl->GetItemCount(), wxEmptyString ); + + wxASSERT( ndx >= 0 ); + + fieldListCtrl->SetItem( ndx, 1, wxEmptyString ); + } + + fieldListCtrl->SetItem( aFieldNdx, 0, aName ); + fieldListCtrl->SetItem( aFieldNdx, 1, aValue ); + + // recompute the column widths here, after setting texts + fieldListCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE ); + fieldListCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE ); +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copySelectedFieldToPanel() +{ + wxCHECK_RET( m_cmp != NULL, wxT( "Component pointer not initialized." ) ); + + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + SCH_FIELD& field = m_FieldsBuf[fieldNdx]; + + showCheckBox->SetValue( field.IsVisible() ); + + rotateCheckBox->SetValue( field.GetOrientation() == TEXT_ORIENT_VERT ); + + int style = 0; + + if( field.IsItalic() ) + style = 1; + + if( field.IsBold() ) + style |= 2; + + m_StyleRadioBox->SetSelection( style ); + + // Select the right text justification + if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT ) + m_FieldHJustifyCtrl->SetSelection( 0 ); + else if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT ) + m_FieldHJustifyCtrl->SetSelection( 2 ); + else + m_FieldHJustifyCtrl->SetSelection( 1 ); + + if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM ) + m_FieldVJustifyCtrl->SetSelection( 0 ); + else if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_TOP ) + m_FieldVJustifyCtrl->SetSelection( 2 ); + else + m_FieldVJustifyCtrl->SetSelection( 1 ); + + + fieldNameTextCtrl->SetValue( field.GetName( false ) ); + + // the names of the fixed fields are not editable, others are. + fieldNameTextCtrl->Enable( fieldNdx >= MANDATORY_FIELDS ); + fieldNameTextCtrl->SetEditable( fieldNdx >= MANDATORY_FIELDS ); + + // only user defined fields may be moved, and not the top most user defined + // field since it would be moving up into the fixed fields, > not >= + moveUpButton->Enable( fieldNdx > MANDATORY_FIELDS ); + + // may only delete user defined fields + deleteFieldButton->Enable( fieldNdx >= MANDATORY_FIELDS ); + + fieldValueTextCtrl->SetValidator( SCH_FIELD_VALIDATOR( false, field.GetId() ) ); + fieldValueTextCtrl->SetValue( field.GetText() ); + + m_show_datasheet_button->Enable( fieldNdx == DATASHEET || fieldNdx == FOOTPRINT ); + + if( fieldNdx == DATASHEET ) + m_show_datasheet_button->SetLabel( _( "Show in Browser" ) ); + else if( fieldNdx == FOOTPRINT ) + m_show_datasheet_button->SetLabel( _( "Assign Footprint" ) ); + else + m_show_datasheet_button->SetLabel( wxEmptyString ); + + // For power symbols, the value is NOR editable, because value and pin + // name must be same and can be edited only in library editor + if( fieldNdx == VALUE && m_part && m_part->IsPower() ) + fieldValueTextCtrl->Enable( false ); + else + fieldValueTextCtrl->Enable( true ); + + textSizeTextCtrl->SetValue( EDA_GRAPHIC_TEXT_CTRL::FormatSize( g_UserUnit, field.GetSize().x ) ); + + wxPoint coord = field.GetTextPosition(); + wxPoint zero = -m_cmp->m_Pos; // relative zero + + // If the field value is empty and the position is at relative zero, we + // set the initial position as a small offset from the ref field, and + // orient it the same as the ref field. That is likely to put it at least + // close to the desired position. + if( coord == zero && field.GetText().IsEmpty() ) + { + rotateCheckBox->SetValue( m_FieldsBuf[REFERENCE].GetOrientation() == TEXT_ORIENT_VERT ); + + coord.x = m_FieldsBuf[REFERENCE].GetTextPosition().x + + ( fieldNdx - MANDATORY_FIELDS + 1 ) * 100; + + coord.y = m_FieldsBuf[REFERENCE].GetTextPosition().y + + ( fieldNdx - MANDATORY_FIELDS + 1 ) * 100; + + // coord can compute negative if field is < MANDATORY_FIELDS, e.g. FOOTPRINT. + // That is ok, we basically don't want all the new empty fields on + // top of each other. + } + + wxString coordText = StringFromValue( g_UserUnit, coord.x ); + posXTextCtrl->SetValue( coordText ); + + coordText = StringFromValue( g_UserUnit, coord.y ); + posYTextCtrl->SetValue( coordText ); +} + + +bool DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyPanelToSelectedField() +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return true; + + // Check for illegal field text. + if( fieldValueTextCtrl->GetValidator() + && !fieldValueTextCtrl->GetValidator()->Validate( this ) ) + return false; + + SCH_FIELD& field = m_FieldsBuf[fieldNdx]; + + field.SetVisible( showCheckBox->GetValue() ); + + if( rotateCheckBox->GetValue() ) + field.SetOrientation( TEXT_ORIENT_VERT ); + else + field.SetOrientation( TEXT_ORIENT_HORIZ ); + + rotateCheckBox->SetValue( field.GetOrientation() == TEXT_ORIENT_VERT ); + + // Copy the text justification + static const EDA_TEXT_HJUSTIFY_T hjustify[] = { + GR_TEXT_HJUSTIFY_LEFT, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_HJUSTIFY_RIGHT + }; + + static const EDA_TEXT_VJUSTIFY_T vjustify[] = { + GR_TEXT_VJUSTIFY_BOTTOM, + GR_TEXT_VJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP + }; + + field.SetHorizJustify( hjustify[m_FieldHJustifyCtrl->GetSelection()] ); + field.SetVertJustify( vjustify[m_FieldVJustifyCtrl->GetSelection()] ); + + field.SetName( fieldNameTextCtrl->GetValue() ); + + /* Void fields texts for REFERENCE and VALUE (value is the name of the + * component in lib ! ) are not allowed + * change them only for a new non void value + * When void, usually netlists are broken + */ + if( !fieldValueTextCtrl->GetValue().IsEmpty() || fieldNdx > VALUE ) + field.SetText( fieldValueTextCtrl->GetValue() ); + + setRowItem( fieldNdx, field ); // update fieldListCtrl + + int tmp = EDA_GRAPHIC_TEXT_CTRL::ParseSize( textSizeTextCtrl->GetValue(), g_UserUnit ); + field.SetSize( wxSize( tmp, tmp ) ); + int style = m_StyleRadioBox->GetSelection(); + + field.SetItalic( (style & 1 ) != 0 ); + field.SetBold( (style & 2 ) != 0 ); + + wxPoint pos; + pos.x = ValueFromString( g_UserUnit, posXTextCtrl->GetValue() ); + pos.y = ValueFromString( g_UserUnit, posYTextCtrl->GetValue() ); + field.SetTextPosition( pos ); + + return true; +} + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyOptionsToPanel() +{ + // Remove non existing choices (choiceCount must be <= number for parts) + int unitcount = m_part ? m_part->GetUnitCount() : 1; + + if( unitcount < 1 ) + unitcount = 1; + + unitChoice->Clear(); + + for( int ii = 1; ii <= unitcount; ii++ ) + { + unitChoice->Append( LIB_PART::SubReference( ii, false ) ); + } + + // For components with multiple parts per package, set the unit selection + if( m_cmp->GetUnit() <= (int)unitChoice->GetCount() ) + unitChoice->SetSelection( m_cmp->GetUnit() - 1 ); + + // Disable unit selection if only one unit exists: + if( m_cmp->GetUnitCount() <= 1 ) + { + unitChoice->Enable( false ); + unitsInterchageableLabel->Show( false ); + unitsInterchageableText->Show( false ); + } + else + { + // Show the "Units are not interchangeable" message option? + if( !m_part || !m_part->UnitsLocked() ) + unitsInterchageableLabel->SetLabel( _( "Yes" ) ); + else + unitsInterchageableLabel->SetLabel( _( "No" ) ); + } + + int orientation = m_cmp->GetOrientation() & ~( CMP_MIRROR_X | CMP_MIRROR_Y ); + + if( orientation == CMP_ORIENT_90 ) + orientationRadioBox->SetSelection( 1 ); + else if( orientation == CMP_ORIENT_180 ) + orientationRadioBox->SetSelection( 2 ); + else if( orientation == CMP_ORIENT_270 ) + orientationRadioBox->SetSelection( 3 ); + else + orientationRadioBox->SetSelection( 0 ); + + int mirror = m_cmp->GetOrientation() & ( CMP_MIRROR_X | CMP_MIRROR_Y ); + + if( mirror == CMP_MIRROR_X ) + { + mirrorRadioBox->SetSelection( 1 ); + DBG( printf( "mirror=X,1\n" ); ) + } + else if( mirror == CMP_MIRROR_Y ) + { + mirrorRadioBox->SetSelection( 2 ); + DBG( printf( "mirror=Y,2\n" ); ) + } + else + mirrorRadioBox->SetSelection( 0 ); + + // Activate/Desactivate the normal/convert option ? (activated only if + // the component has more than one shape) + if( m_cmp->GetConvert() > 1 ) + convertCheckBox->SetValue( true ); + + if( m_part == NULL || !m_part->HasConversion() ) + convertCheckBox->Enable( false ); + + // Set the component's library name. + chipnameTextCtrl->SetValue( m_cmp->m_part_name ); + + // Set the component's unique ID time stamp. + m_textCtrlTimeStamp->SetValue( wxString::Format( wxT( "%8.8lX" ), + (unsigned long) m_cmp->GetTimeStamp() ) ); +} + + +#include + + +void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::SetInitCmp( wxCommandEvent& event ) +{ + if( !m_cmp ) + return; + + if( LIB_PART* part = Prj().SchLibs()->FindLibPart( m_cmp->m_part_name ) ) + { + // save old cmp in undo list if not already in edit, or moving ... + if( m_cmp->m_Flags == 0 ) + m_parent->SaveCopyInUndoList( m_cmp, UR_CHANGED ); + + INSTALL_UNBUFFERED_DC( dc, m_parent->GetCanvas() ); + m_cmp->Draw( m_parent->GetCanvas(), &dc, wxPoint( 0, 0 ), g_XorMode ); + + // Initialize fixed field values to default values found in library + // Note: the field texts are not modified because they are set in schematic, + // the text from libraries is most of time a dummy text + // Only VALUE, REFERENCE , FOOTPRINT and DATASHEET are re-initialized + LIB_FIELD& refField = part->GetReferenceField(); + + m_cmp->GetField( REFERENCE )->SetTextPosition( refField.GetTextPosition() + m_cmp->m_Pos ); + m_cmp->GetField( REFERENCE )->ImportValues( refField ); + + LIB_FIELD& valField = part->GetValueField(); + + m_cmp->GetField( VALUE )->SetTextPosition( valField.GetTextPosition() + m_cmp->m_Pos ); + m_cmp->GetField( VALUE )->ImportValues( valField ); + + LIB_FIELD* field = part->GetField(FOOTPRINT); + + if( field && m_cmp->GetField( FOOTPRINT ) ) + { + m_cmp->GetField( FOOTPRINT )->SetTextPosition( field->GetTextPosition() + m_cmp->m_Pos ); + m_cmp->GetField( FOOTPRINT )->ImportValues( *field ); + } + + field = part->GetField(DATASHEET); + + if( field && m_cmp->GetField( DATASHEET ) ) + { + m_cmp->GetField( DATASHEET )->SetTextPosition( field->GetTextPosition() + m_cmp->m_Pos ); + m_cmp->GetField( DATASHEET )->ImportValues( *field ); + } + + m_cmp->SetOrientation( CMP_NORMAL ); + + m_parent->OnModify(); + + m_cmp->Draw( m_parent->GetCanvas(), &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + + EndQuasiModal( wxID_OK ); + } +} diff --git a/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.cpp b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.cpp new file mode 100644 index 00000000..6dddb57b --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.cpp @@ -0,0 +1,324 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_edit_component_in_schematic_fbp.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP( 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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* upperSizer; + upperSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticBoxSizer* optionsSizer; + optionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Component") ), wxVERTICAL ); + + m_staticTextUnit = new wxStaticText( optionsSizer->GetStaticBox(), wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnit->Wrap( -1 ); + optionsSizer->Add( m_staticTextUnit, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxArrayString unitChoiceChoices; + unitChoice = new wxChoice( optionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, unitChoiceChoices, 0 ); + unitChoice->SetSelection( 0 ); + optionsSizer->Add( unitChoice, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerUnitsInterchangeable; + bSizerUnitsInterchangeable = new wxBoxSizer( wxHORIZONTAL ); + + unitsInterchageableText = new wxStaticText( optionsSizer->GetStaticBox(), wxID_ANY, _("Units are interchangeable:"), wxDefaultPosition, wxDefaultSize, 0 ); + unitsInterchageableText->Wrap( -1 ); + bSizerUnitsInterchangeable->Add( unitsInterchageableText, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + + unitsInterchageableLabel = new wxStaticText( optionsSizer->GetStaticBox(), wxID_ANY, _("Yes"), wxDefaultPosition, wxDefaultSize, 0 ); + unitsInterchageableLabel->Wrap( -1 ); + bSizerUnitsInterchangeable->Add( unitsInterchageableLabel, 0, wxALL, 5 ); + + + optionsSizer->Add( bSizerUnitsInterchangeable, 0, wxEXPAND, 5 ); + + wxString orientationRadioBoxChoices[] = { _("0"), _("+90"), _("180"), _("-90") }; + int orientationRadioBoxNChoices = sizeof( orientationRadioBoxChoices ) / sizeof( wxString ); + orientationRadioBox = new wxRadioBox( optionsSizer->GetStaticBox(), wxID_ANY, _("Orientation (Degrees)"), wxDefaultPosition, wxDefaultSize, orientationRadioBoxNChoices, orientationRadioBoxChoices, 1, wxRA_SPECIFY_COLS ); + orientationRadioBox->SetSelection( 0 ); + orientationRadioBox->SetToolTip( _("Select if the component is to be rotated when drawn") ); + + optionsSizer->Add( orientationRadioBox, 0, wxEXPAND|wxALL, 5 ); + + wxString mirrorRadioBoxChoices[] = { _("Normal"), _("Mirror ---"), _("Mirror |") }; + int mirrorRadioBoxNChoices = sizeof( mirrorRadioBoxChoices ) / sizeof( wxString ); + mirrorRadioBox = new wxRadioBox( optionsSizer->GetStaticBox(), wxID_ANY, _("Mirror"), wxDefaultPosition, wxDefaultSize, mirrorRadioBoxNChoices, mirrorRadioBoxChoices, 1, wxRA_SPECIFY_COLS ); + mirrorRadioBox->SetSelection( 0 ); + mirrorRadioBox->SetToolTip( _("Pick the graphical transformation to be used when displaying the component, if any") ); + + optionsSizer->Add( mirrorRadioBox, 0, wxALL|wxEXPAND, 5 ); + + convertCheckBox = new wxCheckBox( optionsSizer->GetStaticBox(), wxID_ANY, _("Converted Shape"), wxDefaultPosition, wxDefaultSize, 0 ); + convertCheckBox->SetToolTip( _("Use the alternate shape of this component.\nFor gates, this is the \"De Morgan\" conversion") ); + + optionsSizer->Add( convertCheckBox, 0, wxALL, 5 ); + + wxStaticBoxSizer* sbSizerChipName; + sbSizerChipName = new wxStaticBoxSizer( new wxStaticBox( optionsSizer->GetStaticBox(), wxID_ANY, _("Chip Name") ), wxVERTICAL ); + + chipnameTextCtrl = new wxTextCtrl( sbSizerChipName->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + chipnameTextCtrl->SetToolTip( _("The name of the symbol in the library from which this component came") ); + + sbSizerChipName->Add( chipnameTextCtrl, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + wxBoxSizer* bSizerChpinameButt; + bSizerChpinameButt = new wxBoxSizer( wxHORIZONTAL ); + + m_buttonTestChipName = new wxButton( sbSizerChipName->GetStaticBox(), wxID_ANY, _("Test"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerChpinameButt->Add( m_buttonTestChipName, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_buttonSelectChipName = new wxButton( sbSizerChipName->GetStaticBox(), wxID_ANY, _("Select"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerChpinameButt->Add( m_buttonSelectChipName, 0, wxTOP|wxBOTTOM, 5 ); + + + sbSizerChipName->Add( bSizerChpinameButt, 1, wxEXPAND, 5 ); + + + optionsSizer->Add( sbSizerChipName, 0, wxEXPAND|wxALL, 5 ); + + m_staticTextTimeStamp = new wxStaticText( optionsSizer->GetStaticBox(), wxID_ANY, _("Timestamp"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeStamp->Wrap( -1 ); + optionsSizer->Add( m_staticTextTimeStamp, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_textCtrlTimeStamp = new wxTextCtrl( optionsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + m_textCtrlTimeStamp->SetToolTip( _("An unique ID (a time stamp) to identify the component.\nThis is an alternate identifier to the reference.") ); + + optionsSizer->Add( m_textCtrlTimeStamp, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( optionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + optionsSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + defaultsButton = new wxButton( optionsSizer->GetStaticBox(), wxID_ANY, _("Reset to Library Defaults"), wxDefaultPosition, wxDefaultSize, 0 ); + defaultsButton->SetToolTip( _("Set position and style of fields and component orientation to default lib value.\nFields texts are not modified.") ); + + optionsSizer->Add( defaultsButton, 0, wxALL|wxEXPAND, 5 ); + + + upperSizer->Add( optionsSizer, 0, wxEXPAND|wxALL, 5 ); + + wxStaticBoxSizer* fieldsSizer; + fieldsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Fields") ), wxHORIZONTAL ); + + wxStaticBoxSizer* gridStaticBoxSizer; + gridStaticBoxSizer = new wxStaticBoxSizer( new wxStaticBox( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString ), wxVERTICAL ); + + fieldListCtrl = new wxListCtrl( gridStaticBoxSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES ); + fieldListCtrl->SetMinSize( wxSize( 220,-1 ) ); + + gridStaticBoxSizer->Add( fieldListCtrl, 1, wxALL|wxEXPAND, 8 ); + + addFieldButton = new wxButton( gridStaticBoxSizer->GetStaticBox(), wxID_ANY, _("Add Field"), wxDefaultPosition, wxDefaultSize, 0 ); + addFieldButton->SetToolTip( _("Add a new custom field") ); + + gridStaticBoxSizer->Add( addFieldButton, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + deleteFieldButton = new wxButton( gridStaticBoxSizer->GetStaticBox(), wxID_ANY, _("Delete Field"), wxDefaultPosition, wxDefaultSize, 0 ); + deleteFieldButton->SetToolTip( _("Delete one of the optional fields") ); + + gridStaticBoxSizer->Add( deleteFieldButton, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + moveUpButton = new wxButton( gridStaticBoxSizer->GetStaticBox(), wxID_ANY, _("Move Up"), wxDefaultPosition, wxDefaultSize, 0 ); + moveUpButton->SetToolTip( _("Move the selected optional fields up one position") ); + + gridStaticBoxSizer->Add( moveUpButton, 0, wxALL|wxEXPAND, 5 ); + + + fieldsSizer->Add( gridStaticBoxSizer, 3, wxEXPAND|wxRIGHT|wxLEFT, 8 ); + + wxBoxSizer* fieldEditBoxSizer; + fieldEditBoxSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerJustification; + bSizerJustification = new wxBoxSizer( wxHORIZONTAL ); + + wxString m_FieldHJustifyCtrlChoices[] = { _("Left"), _("Center"), _("Right") }; + int m_FieldHJustifyCtrlNChoices = sizeof( m_FieldHJustifyCtrlChoices ) / sizeof( wxString ); + m_FieldHJustifyCtrl = new wxRadioBox( fieldsSizer->GetStaticBox(), wxID_ANY, _("Horiz. Justify"), wxDefaultPosition, wxDefaultSize, m_FieldHJustifyCtrlNChoices, m_FieldHJustifyCtrlChoices, 1, wxRA_SPECIFY_COLS ); + m_FieldHJustifyCtrl->SetSelection( 2 ); + bSizerJustification->Add( m_FieldHJustifyCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + wxString m_FieldVJustifyCtrlChoices[] = { _("Bottom"), _("Center"), _("Top") }; + int m_FieldVJustifyCtrlNChoices = sizeof( m_FieldVJustifyCtrlChoices ) / sizeof( wxString ); + m_FieldVJustifyCtrl = new wxRadioBox( fieldsSizer->GetStaticBox(), wxID_ANY, _("Vert. Justify"), wxDefaultPosition, wxDefaultSize, m_FieldVJustifyCtrlNChoices, m_FieldVJustifyCtrlChoices, 1, wxRA_SPECIFY_COLS ); + m_FieldVJustifyCtrl->SetSelection( 2 ); + bSizerJustification->Add( m_FieldVJustifyCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + + fieldEditBoxSizer->Add( bSizerJustification, 1, wxEXPAND|wxBOTTOM, 5 ); + + wxBoxSizer* bSizerStyle; + bSizerStyle = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticBoxSizer* visibilitySizer; + visibilitySizer = new wxStaticBoxSizer( new wxStaticBox( fieldsSizer->GetStaticBox(), wxID_ANY, _("Visibility") ), wxVERTICAL ); + + showCheckBox = new wxCheckBox( visibilitySizer->GetStaticBox(), wxID_ANY, _("Show"), wxDefaultPosition, wxDefaultSize, 0 ); + showCheckBox->SetToolTip( _("Check if you want this field visible") ); + + visibilitySizer->Add( showCheckBox, 0, wxALL, 5 ); + + rotateCheckBox = new wxCheckBox( visibilitySizer->GetStaticBox(), wxID_ANY, _("Rotate"), wxDefaultPosition, wxDefaultSize, 0 ); + rotateCheckBox->SetToolTip( _("Check if you want this field's text rotated 90 degrees") ); + + visibilitySizer->Add( rotateCheckBox, 0, wxALL, 5 ); + + + bSizerStyle->Add( visibilitySizer, 1, wxEXPAND|wxALL, 5 ); + + wxString m_StyleRadioBoxChoices[] = { _("Normal"), _("Italic"), _("Bold"), _("Bold Italic") }; + int m_StyleRadioBoxNChoices = sizeof( m_StyleRadioBoxChoices ) / sizeof( wxString ); + m_StyleRadioBox = new wxRadioBox( fieldsSizer->GetStaticBox(), wxID_ANY, _("Style:"), wxDefaultPosition, wxDefaultSize, m_StyleRadioBoxNChoices, m_StyleRadioBoxChoices, 1, wxRA_SPECIFY_COLS ); + m_StyleRadioBox->SetSelection( 3 ); + m_StyleRadioBox->SetToolTip( _("The style of the currently selected field's text in the schematic") ); + + bSizerStyle->Add( m_StyleRadioBox, 1, wxEXPAND|wxALL, 5 ); + + + fieldEditBoxSizer->Add( bSizerStyle, 1, wxEXPAND|wxBOTTOM, 5 ); + + wxBoxSizer* fieldNameBoxSizer; + fieldNameBoxSizer = new wxBoxSizer( wxVERTICAL ); + + fieldNameLabel = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("Field Name"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldNameLabel->Wrap( -1 ); + fieldNameBoxSizer->Add( fieldNameLabel, 0, wxTOP, 5 ); + + fieldNameTextCtrl = new wxTextCtrl( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fieldNameTextCtrl->SetToolTip( _("The name of the currently selected field\nSome fixed fields names are not editable") ); + + fieldNameBoxSizer->Add( fieldNameTextCtrl, 0, wxBOTTOM|wxEXPAND, 5 ); + + fieldValueLabel = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("Field Value"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldValueLabel->Wrap( -1 ); + fieldNameBoxSizer->Add( fieldValueLabel, 0, wxALIGN_TOP|wxTOP, 5 ); + + fieldValueTextCtrl = new wxTextCtrl( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fieldValueTextCtrl->SetToolTip( _("The name of the currently selected field\nSome fixed fields names are not editable") ); + + fieldNameBoxSizer->Add( fieldValueTextCtrl, 0, wxEXPAND|wxBOTTOM, 5 ); + + m_show_datasheet_button = new wxButton( fieldsSizer->GetStaticBox(), wxID_ANY, _("Show in Browser"), wxDefaultPosition, wxDefaultSize, 0 ); + m_show_datasheet_button->SetToolTip( _("If your datasheet is an http:// link or a complete file path, then it may show in your browser by pressing this button.") ); + + fieldNameBoxSizer->Add( m_show_datasheet_button, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + + fieldEditBoxSizer->Add( fieldNameBoxSizer, 0, wxBOTTOM|wxEXPAND, 5 ); + + wxFlexGridSizer* fgSizerPosSize; + fgSizerPosSize = new wxFlexGridSizer( 3, 3, 0, 0 ); + fgSizerPosSize->AddGrowableCol( 1 ); + fgSizerPosSize->SetFlexibleDirection( wxBOTH ); + fgSizerPosSize->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + textSizeLabel = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("Size"), wxDefaultPosition, wxDefaultSize, 0 ); + textSizeLabel->Wrap( -1 ); + fgSizerPosSize->Add( textSizeLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + textSizeTextCtrl = new wxTextCtrl( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + textSizeTextCtrl->SetToolTip( _("The size of the currently selected field's text in the schematic") ); + + fgSizerPosSize->Add( textSizeTextCtrl, 0, wxEXPAND|wxBOTTOM, 5 ); + + m_staticTextUnitSize = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitSize->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitSize, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + posXLabel = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("PosX"), wxDefaultPosition, wxDefaultSize, 0 ); + posXLabel->Wrap( -1 ); + fgSizerPosSize->Add( posXLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posXTextCtrl = new wxTextCtrl( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + posXTextCtrl->SetToolTip( _("The X coordinate of the text relative to the component") ); + + fgSizerPosSize->Add( posXTextCtrl, 0, wxEXPAND|wxTOP, 5 ); + + m_staticTextUnitPosX = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitPosX->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitPosX, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + posYLabel = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("PosY"), wxDefaultPosition, wxDefaultSize, 0 ); + posYLabel->Wrap( -1 ); + fgSizerPosSize->Add( posYLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posYTextCtrl = new wxTextCtrl( fieldsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + posYTextCtrl->SetToolTip( _("The Y coordinate of the text relative to the component") ); + + fgSizerPosSize->Add( posYTextCtrl, 0, wxEXPAND, 5 ); + + m_staticTextUnitPosY = new wxStaticText( fieldsSizer->GetStaticBox(), wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitPosY->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitPosY, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + fieldEditBoxSizer->Add( fgSizerPosSize, 1, wxEXPAND|wxTOP, 5 ); + + + fieldsSizer->Add( fieldEditBoxSizer, 2, wxEXPAND, 5 ); + + + upperSizer->Add( fieldsSizer, 1, wxALL|wxEXPAND, 5 ); + + + mainSizer->Add( upperSizer, 1, wxEXPAND, 5 ); + + stdDialogButtonSizer = new wxStdDialogButtonSizer(); + stdDialogButtonSizerOK = new wxButton( this, wxID_OK ); + stdDialogButtonSizer->AddButton( stdDialogButtonSizerOK ); + stdDialogButtonSizerCancel = new wxButton( this, wxID_CANCEL ); + stdDialogButtonSizer->AddButton( stdDialogButtonSizerCancel ); + stdDialogButtonSizer->Realize(); + + mainSizer->Add( stdDialogButtonSizer, 0, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnCloseDialog ) ); + this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnInitDlg ) ); + m_buttonTestChipName->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnTestChipName ), NULL, this ); + m_buttonSelectChipName->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnSelectChipName ), NULL, this ); + defaultsButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::SetInitCmp ), NULL, this ); + fieldListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnListItemDeselected ), NULL, this ); + fieldListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnListItemSelected ), NULL, this ); + addFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::addFieldButtonHandler ), NULL, this ); + deleteFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::deleteFieldButtonHandler ), NULL, this ); + moveUpButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::moveUpButtonHandler ), NULL, this ); + m_show_datasheet_button->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::showButtonHandler ), NULL, this ); + stdDialogButtonSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnCancelButtonClick ), NULL, this ); + stdDialogButtonSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnOKButtonClick ), NULL, this ); +} + +DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::~DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnCloseDialog ) ); + this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnInitDlg ) ); + m_buttonTestChipName->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnTestChipName ), NULL, this ); + m_buttonSelectChipName->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnSelectChipName ), NULL, this ); + defaultsButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::SetInitCmp ), NULL, this ); + fieldListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnListItemDeselected ), NULL, this ); + fieldListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnListItemSelected ), NULL, this ); + addFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::addFieldButtonHandler ), NULL, this ); + deleteFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::deleteFieldButtonHandler ), NULL, this ); + moveUpButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::moveUpButtonHandler ), NULL, this ); + m_show_datasheet_button->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::showButtonHandler ), NULL, this ); + stdDialogButtonSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnCancelButtonClick ), NULL, this ); + stdDialogButtonSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP::OnOKButtonClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.fbp b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.fbp new file mode 100644 index 00000000..d46b0b57 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.fbp @@ -0,0 +1,3532 @@ + + + + + ; + C++ + 1 + source_name + 0 + 0 + res + ANSI + connect + dialog_edit_component_in_schematic_fbp + 1000 + none + 1 + dialog_edit_component_in_schematic_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP + + 688,586 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU + DIALOG_SHIM; dialog_shim.h + Component Properties + + + + + + + + + + + + + + OnCloseDialog + + + + + + OnInitDlg + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + upperSizer + wxHORIZONTAL + none + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + Component + + optionsSizer + wxVERTICAL + 1 + none + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Unit + + 0 + + + 0 + + 1 + m_staticTextUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + unitChoice + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizerUnitsInterchangeable + wxHORIZONTAL + none + + 5 + wxTOP|wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Units are interchangeable: + + 0 + + + 0 + + 1 + unitsInterchageableText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Yes + + 0 + + + 0 + + 1 + unitsInterchageableLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "0" "+90" "180" "-90" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Orientation (Degrees) + 1 + + 0 + + + 0 + + 1 + orientationRadioBox + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + Select if the component is to be rotated when drawn + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Normal" "Mirror ---" "Mirror |" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Mirror + 1 + + 0 + + + 0 + + 1 + mirrorRadioBox + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + Pick the graphical transformation to be used when displaying the component, if any + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Converted Shape + + 0 + + + 0 + + 1 + convertCheckBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Use the alternate shape of this component. For gates, this is the "De Morgan" conversion + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + Chip Name + + sbSizerChipName + wxVERTICAL + 1 + none + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + chipnameTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The name of the symbol in the library from which this component came + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerChpinameButt + wxHORIZONTAL + none + + 5 + wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Test + + 0 + + + 0 + + 1 + m_buttonTestChipName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnTestChipName + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select + + 0 + + + 0 + + 1 + m_buttonSelectChipName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnSelectChipName + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Timestamp + + 0 + + + 0 + + 1 + m_staticTextTimeStamp + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrlTimeStamp + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + An unique ID (a time stamp) to identify the component. This is an alternate identifier to the reference. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Reset to Library Defaults + + 0 + + + 0 + + 1 + defaultsButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Set position and style of fields and component orientation to default lib value. Fields texts are not modified. + + wxFILTER_NONE + wxDefaultValidator + + + + + SetInitCmp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Fields + + fieldsSizer + wxHORIZONTAL + 1 + none + + + 8 + wxEXPAND|wxRIGHT|wxLEFT + 3 + + wxID_ANY + + + gridStaticBoxSizer + wxVERTICAL + 1 + none + + + 8 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 220,-1 + 1 + fieldListCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemDeselected + + + + OnListItemSelected + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Add Field + + 0 + + + 0 + + 1 + addFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a new custom field + + wxFILTER_NONE + wxDefaultValidator + + + + + addFieldButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Delete Field + + 0 + + + 0 + + 1 + deleteFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Delete one of the optional fields + + wxFILTER_NONE + wxDefaultValidator + + + + + deleteFieldButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Move Up + + 0 + + + 0 + + 1 + moveUpButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the selected optional fields up one position + + wxFILTER_NONE + wxDefaultValidator + + + + + moveUpButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 2 + + + fieldEditBoxSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxBOTTOM + 1 + + + bSizerJustification + wxHORIZONTAL + none + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Left" "Center" "Right" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Horiz. Justify + 1 + + 0 + + + 0 + + 1 + m_FieldHJustifyCtrl + 1 + + + protected + 1 + + Resizable + 2 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Bottom" "Center" "Top" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Vert. Justify + 1 + + 0 + + + 0 + + 1 + m_FieldVJustifyCtrl + 1 + + + protected + 1 + + Resizable + 2 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM + 1 + + + bSizerStyle + wxHORIZONTAL + none + + 5 + wxEXPAND|wxALL + 1 + + wxID_ANY + Visibility + + visibilitySizer + wxVERTICAL + 1 + none + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show + + 0 + + + 0 + + 1 + showCheckBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check if you want this field visible + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Rotate + + 0 + + + 0 + + 1 + rotateCheckBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check if you want this field's text rotated 90 degrees + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Normal" "Italic" "Bold" "Bold Italic" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Style: + 1 + + 0 + + + 0 + + 1 + m_StyleRadioBox + 1 + + + protected + 1 + + Resizable + 3 + 1 + + wxRA_SPECIFY_COLS + + 0 + The style of the currently selected field's text in the schematic + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND + 0 + + + fieldNameBoxSizer + wxVERTICAL + none + + 5 + wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Field Name + + 0 + + + 0 + + 1 + fieldNameLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldNameTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The name of the currently selected field Some fixed fields names are not editable + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_TOP|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Field Value + + 0 + + + 0 + + 1 + fieldValueLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldValueTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The name of the currently selected field Some fixed fields names are not editable + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show in Browser + + 0 + + + 0 + + 1 + m_show_datasheet_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + If your datasheet is an http:// link or a complete file path, then it may show in your browser by pressing this button. + + wxFILTER_NONE + wxDefaultValidator + + + + + showButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP + 1 + + 3 + wxBOTH + 1 + + 0 + + fgSizerPosSize + wxFLEX_GROWMODE_SPECIFIED + none + 3 + 0 + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size + + 0 + + + 0 + + 1 + textSizeLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + textSizeTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The size of the currently selected field's text in the schematic + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + PosX + + 0 + + + 0 + + 1 + posXLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + posXTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The X coordinate of the text relative to the component + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitPosX + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + PosY + + 0 + + + 0 + + 1 + posYLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + posYTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The Y coordinate of the text relative to the component + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitPosY + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + stdDialogButtonSizer + protected + + OnCancelButtonClick + + + + OnOKButtonClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.h b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.h new file mode 100644 index 00000000..4e500647 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_component_in_schematic_fbp.h @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP_H__ +#define __DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticTextUnit; + wxChoice* unitChoice; + wxStaticText* unitsInterchageableText; + wxStaticText* unitsInterchageableLabel; + wxRadioBox* orientationRadioBox; + wxRadioBox* mirrorRadioBox; + wxCheckBox* convertCheckBox; + wxTextCtrl* chipnameTextCtrl; + wxButton* m_buttonTestChipName; + wxButton* m_buttonSelectChipName; + wxStaticText* m_staticTextTimeStamp; + wxTextCtrl* m_textCtrlTimeStamp; + wxStaticLine* m_staticline1; + wxButton* defaultsButton; + wxListCtrl* fieldListCtrl; + wxButton* addFieldButton; + wxButton* deleteFieldButton; + wxButton* moveUpButton; + wxRadioBox* m_FieldHJustifyCtrl; + wxRadioBox* m_FieldVJustifyCtrl; + wxCheckBox* showCheckBox; + wxCheckBox* rotateCheckBox; + wxRadioBox* m_StyleRadioBox; + wxStaticText* fieldNameLabel; + wxTextCtrl* fieldNameTextCtrl; + wxStaticText* fieldValueLabel; + wxTextCtrl* fieldValueTextCtrl; + wxButton* m_show_datasheet_button; + wxStaticText* textSizeLabel; + wxTextCtrl* textSizeTextCtrl; + wxStaticText* m_staticTextUnitSize; + wxStaticText* posXLabel; + wxTextCtrl* posXTextCtrl; + wxStaticText* m_staticTextUnitPosX; + wxStaticText* posYLabel; + wxTextCtrl* posYTextCtrl; + wxStaticText* m_staticTextUnitPosY; + wxStdDialogButtonSizer* stdDialogButtonSizer; + wxButton* stdDialogButtonSizerOK; + wxButton* stdDialogButtonSizerCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); } + virtual void OnInitDlg( wxInitDialogEvent& event ) { event.Skip(); } + virtual void OnTestChipName( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSelectChipName( wxCommandEvent& event ) { event.Skip(); } + virtual void SetInitCmp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnListItemDeselected( wxListEvent& event ) { event.Skip(); } + virtual void OnListItemSelected( wxListEvent& event ) { event.Skip(); } + virtual void addFieldButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void deleteFieldButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void moveUpButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void showButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Component Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 688,586 ), long style = wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU ); + ~DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP(); + +}; + +#endif //__DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_FBP_H__ diff --git a/eeschema/dialogs/dialog_edit_label.cpp b/eeschema/dialogs/dialog_edit_label.cpp new file mode 100644 index 00000000..0f70dced --- /dev/null +++ b/eeschema/dialogs/dialog_edit_label.cpp @@ -0,0 +1,326 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2013 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 + */ + +/** + * @file sch_text.h + * @brief Implementation of the label properties dialog. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +class SCH_EDIT_FRAME; +class SCH_TEXT; + + +class DIALOG_LABEL_EDITOR : public DIALOG_LABEL_EDITOR_BASE +{ +public: + DIALOG_LABEL_EDITOR( SCH_EDIT_FRAME* parent, SCH_TEXT* aTextItem ); + + void SetTitle( const wxString& aTitle ) // OVERRIDE wxTopLevelWindow::SetTitle + { + // This class is shared for numerous tasks: a couple of + // single line labels and multi-line text fields. + // Often the desired size of the multi-line text field editor + // is larger than is needed for the single line label. + // Therefore the session retained sizes of these dialogs needs + // to be class independent, make them title dependent. + switch( m_CurrentText->Type() ) + { + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_LABEL_T: + // labels can share retained settings probably. + break; + + default: + m_hash_key = TO_UTF8( aTitle ); + m_hash_key += typeid(*this).name(); + } + + DIALOG_LABEL_EDITOR_BASE::SetTitle( aTitle ); + } + +private: + void InitDialog( ); + virtual void OnEnterKey( wxCommandEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); + void TextPropertiesAccept( wxCommandEvent& aEvent ); + + SCH_EDIT_FRAME* m_Parent; + SCH_TEXT* m_CurrentText; + wxTextCtrl* m_textLabel; +}; + + + +/* Edit the properties of the text (Label, Global label, graphic text).. ) + * pointed by "aTextStruct" + */ +void SCH_EDIT_FRAME::EditSchematicText( SCH_TEXT* aTextItem ) +{ + if( aTextItem == NULL ) + return; + + DIALOG_LABEL_EDITOR dialog( this, aTextItem ); + + dialog.ShowModal(); +} + + +DIALOG_LABEL_EDITOR::DIALOG_LABEL_EDITOR( SCH_EDIT_FRAME* aParent, SCH_TEXT* aTextItem ) : + DIALOG_LABEL_EDITOR_BASE( aParent ) +{ + m_Parent = aParent; + m_CurrentText = aTextItem; + InitDialog(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_LABEL_EDITOR::InitDialog() +{ + wxString msg; + bool multiLine = false; + + if( m_CurrentText->IsMultilineAllowed() ) + { + m_textLabel = m_textLabelMultiLine; + m_textLabelSingleLine->Show( false ); + multiLine = true; + } + else + { + m_textLabel = m_textLabelSingleLine; + m_textLabelMultiLine->Show( false ); + wxTextValidator* validator = (wxTextValidator*) m_textLabel->GetValidator(); + wxArrayString excludes; + + // Add invalid label characters to this list. + excludes.Add( wxT( " " ) ); + validator->SetExcludes( excludes ); + } + + m_textLabel->SetValue( m_CurrentText->GetText() ); + m_textLabel->SetFocus(); + + switch( m_CurrentText->Type() ) + { + case SCH_GLOBAL_LABEL_T: + SetTitle( _( "Global Label Properties" ) ); + break; + + case SCH_HIERARCHICAL_LABEL_T: + SetTitle( _( "Hierarchical Label Properties" ) ); + break; + + case SCH_LABEL_T: + SetTitle( _( "Label Properties" ) ); + break; + + case SCH_SHEET_PIN_T: + SetTitle( _( "Hierarchical Sheet Pin Properties." ) ); + break; + + default: + SetTitle( _( "Text Properties" ) ); + break; + } + + const int MINTEXTWIDTH = 40; // M's are big characters, a few establish a lot of width + + int max_len = 0; + + if ( !multiLine ) + { + max_len = m_CurrentText->GetText().Length(); + } + else + { + // calculate the length of the biggest line + // we cannot use the length of the entire text that has no meaning + int curr_len = MINTEXTWIDTH; + int imax = m_CurrentText->GetText().Length(); + + for( int count = 0; count < imax; count++ ) + { + if( m_CurrentText->GetText()[count] == '\n' || + m_CurrentText->GetText()[count] == '\r' ) // new line + { + curr_len = 0; + } + else + { + curr_len++; + + if ( max_len < curr_len ) + max_len = curr_len; + } + } + } + + if( max_len < MINTEXTWIDTH ) + max_len = MINTEXTWIDTH; + + wxString textWidth; + textWidth.Append( 'M', MINTEXTWIDTH ); + EnsureTextCtrlWidth( m_textLabel, &textWidth ); + + // Set validators + m_TextOrient->SetSelection( m_CurrentText->GetOrientation() ); + m_TextShape->SetSelection( m_CurrentText->GetShape() ); + + int style = 0; + + if( m_CurrentText->IsItalic() ) + style = 1; + + if( m_CurrentText->IsBold() ) + style += 2; + + m_TextStyle->SetSelection( style ); + + wxString units = ReturnUnitSymbol( g_UserUnit, wxT( "(%s)" ) ); + msg.Printf( _( "H%s x W%s" ), GetChars( units ), GetChars( units ) ); + m_staticSizeUnits->SetLabel( msg ); + + msg = StringFromValue( g_UserUnit, m_CurrentText->GetSize().x ); + m_TextSize->SetValue( msg ); + + if( m_CurrentText->Type() != SCH_GLOBAL_LABEL_T + && m_CurrentText->Type() != SCH_HIERARCHICAL_LABEL_T ) + { + m_TextShape->Show( false ); + } + + m_sdbSizer1OK->SetDefault(); +} + + +/*! + * wxTE_PROCESS_ENTER event handler for m_textLabel + */ + +void DIALOG_LABEL_EDITOR::OnEnterKey( wxCommandEvent& aEvent ) +{ + TextPropertiesAccept( aEvent ); +} + + +/*! + * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK + */ + +void DIALOG_LABEL_EDITOR::OnOkClick( wxCommandEvent& aEvent ) +{ + TextPropertiesAccept( aEvent ); +} + + +/*! + * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_CANCEL + */ + +void DIALOG_LABEL_EDITOR::OnCancelClick( wxCommandEvent& aEvent ) +{ + m_Parent->GetCanvas()->MoveCursorToCrossHair(); + EndModal( wxID_CANCEL ); +} + + +void DIALOG_LABEL_EDITOR::TextPropertiesAccept( wxCommandEvent& aEvent ) +{ + wxString text; + int value; + + /* save old text in undo list if not already in edit */ + /* or the label to be edited is part of a block */ + if( m_CurrentText->GetFlags() == 0 || + m_Parent->GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + m_Parent->SaveCopyInUndoList( m_CurrentText, UR_CHANGED ); + + m_Parent->GetCanvas()->RefreshDrawingRect( m_CurrentText->GetBoundingBox() ); + + text = m_textLabel->GetValue(); + + if( !text.IsEmpty() ) + m_CurrentText->SetText( text ); + else if( !m_CurrentText->IsNew() ) + { + DisplayError( this, _( "Empty Text!" ) ); + return; + } + + m_CurrentText->SetOrientation( m_TextOrient->GetSelection() ); + text = m_TextSize->GetValue(); + value = ValueFromString( g_UserUnit, text ); + m_CurrentText->SetSize( wxSize( value, value ) ); + + if( m_TextShape ) + /// @todo move cast to widget + m_CurrentText->SetShape( m_TextShape->GetSelection() ); + + int style = m_TextStyle->GetSelection(); + + m_CurrentText->SetItalic( ( style & 1 ) ); + + if( ( style & 2 ) ) + { + m_CurrentText->SetBold( true ); + m_CurrentText->SetThickness( GetPenSizeForBold( m_CurrentText->GetSize().x ) ); + } + else + { + m_CurrentText->SetBold( false ); + m_CurrentText->SetThickness( 0 ); + } + + m_Parent->OnModify(); + + // Make the text size the new default size ( if it is a new text ): + if( m_CurrentText->IsNew() ) + SetDefaultTextSize( m_CurrentText->GetSize().x ); + + m_Parent->GetCanvas()->RefreshDrawingRect( m_CurrentText->GetBoundingBox() ); + m_Parent->GetCanvas()->MoveCursorToCrossHair(); + EndModal( wxID_OK ); +} diff --git a/eeschema/dialogs/dialog_edit_label_base.cpp b/eeschema/dialogs/dialog_edit_label_base.cpp new file mode 100644 index 00000000..f223491d --- /dev/null +++ b/eeschema/dialogs/dialog_edit_label_base.cpp @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Feb 26 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_edit_label_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LABEL_EDITOR_BASE::DIALOG_LABEL_EDITOR_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + m_textControlSizer = new wxFlexGridSizer( 2, 2, 3, 3 ); + m_textControlSizer->AddGrowableCol( 1 ); + m_textControlSizer->AddGrowableRow( 0 ); + m_textControlSizer->SetFlexibleDirection( wxBOTH ); + m_textControlSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("&Text:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + m_staticText1->SetToolTip( _("Enter the text to be used within the schematic") ); + + m_textControlSizer->Add( m_staticText1, 0, wxRIGHT, 3 ); + + wxBoxSizer* bSizeText; + bSizeText = new wxBoxSizer( wxVERTICAL ); + + m_textLabelSingleLine = new wxTextCtrl( this, wxID_VALUESINGLE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + m_textLabelSingleLine->SetValidator( wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, &m_labelText ) ); + + bSizeText->Add( m_textLabelSingleLine, 0, wxEXPAND|wxLEFT, 3 ); + + m_textLabelMultiLine = new wxTextCtrl( this, wxID_VALUEMULTI, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); + m_textLabelMultiLine->SetMinSize( wxSize( -1,60 ) ); + + bSizeText->Add( m_textLabelMultiLine, 1, wxEXPAND|wxLEFT, 3 ); + + + m_textControlSizer->Add( bSizeText, 1, wxEXPAND, 3 ); + + m_SizeTitle = new wxStaticText( this, wxID_ANY, _("&Size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeTitle->Wrap( -1 ); + m_textControlSizer->Add( m_SizeTitle, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3 ); + + wxBoxSizer* bSizeCtrlSizer; + bSizeCtrlSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_TextSize = new wxTextCtrl( this, wxID_SIZE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizeCtrlSizer->Add( m_TextSize, 0, wxEXPAND|wxLEFT|wxRIGHT, 3 ); + + m_staticSizeUnits = new wxStaticText( this, wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticSizeUnits->Wrap( -1 ); + bSizeCtrlSizer->Add( m_staticSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 3 ); + + + m_textControlSizer->Add( bSizeCtrlSizer, 1, wxEXPAND, 3 ); + + + bMainSizer->Add( m_textControlSizer, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 12 ); + + wxBoxSizer* m_OptionsSizer; + m_OptionsSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxString m_TextOrientChoices[] = { _("Right"), _("Up"), _("Left"), _("Down") }; + int m_TextOrientNChoices = sizeof( m_TextOrientChoices ) / sizeof( wxString ); + m_TextOrient = new wxRadioBox( this, wxID_ANY, _("O&rientation"), wxDefaultPosition, wxDefaultSize, m_TextOrientNChoices, m_TextOrientChoices, 1, wxRA_SPECIFY_COLS ); + m_TextOrient->SetSelection( 0 ); + m_OptionsSizer->Add( m_TextOrient, 1, wxRIGHT|wxTOP, 3 ); + + wxString m_TextStyleChoices[] = { _("Normal"), _("Italic"), _("Bold"), _("Bold Italic") }; + int m_TextStyleNChoices = sizeof( m_TextStyleChoices ) / sizeof( wxString ); + m_TextStyle = new wxRadioBox( this, wxID_ANY, _("St&yle"), wxDefaultPosition, wxDefaultSize, m_TextStyleNChoices, m_TextStyleChoices, 1, wxRA_SPECIFY_COLS ); + m_TextStyle->SetSelection( 0 ); + m_OptionsSizer->Add( m_TextStyle, 1, wxLEFT|wxRIGHT|wxTOP, 3 ); + + wxString m_TextShapeChoices[] = { _("Input"), _("Output"), _("Bidirectional"), _("Tri-State"), _("Passive") }; + int m_TextShapeNChoices = sizeof( m_TextShapeChoices ) / sizeof( wxString ); + m_TextShape = new wxRadioBox( this, wxID_ANY, _("S&hape"), wxDefaultPosition, wxDefaultSize, m_TextShapeNChoices, m_TextShapeChoices, 1, wxRA_SPECIFY_COLS ); + m_TextShape->SetSelection( 0 ); + m_OptionsSizer->Add( m_TextShape, 1, wxALL|wxLEFT|wxTOP, 3 ); + + + bMainSizer->Add( m_OptionsSizer, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 12 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + bMainSizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 12 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + // Connect Events + m_textLabelSingleLine->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnEnterKey ), NULL, this ); + m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnCancelClick ), NULL, this ); + m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_LABEL_EDITOR_BASE::~DIALOG_LABEL_EDITOR_BASE() +{ + // Disconnect Events + m_textLabelSingleLine->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnEnterKey ), NULL, this ); + m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnCancelClick ), NULL, this ); + m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LABEL_EDITOR_BASE::OnOkClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_edit_label_base.fbp b/eeschema/dialogs/dialog_edit_label_base.fbp new file mode 100644 index 00000000..609c4840 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_label_base.fbp @@ -0,0 +1,968 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_edit_label_base + 1000 + none + 1 + dialog_edit_label_base + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LABEL_EDITOR_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Text Editor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 12 + wxEXPAND|wxLEFT|wxRIGHT|wxTOP + 1 + + 2 + wxBOTH + 1 + 0 + 3 + + m_textControlSizer + wxFLEX_GROWMODE_SPECIFIED + protected + 2 + 3 + + 3 + wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Text: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Enter the text to be used within the schematic + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 1 + + -1,-1 + bSizeText + wxVERTICAL + none + + 3 + wxEXPAND|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_VALUESINGLE + + 0 + + + + 0 + + 1 + m_textLabelSingleLine + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + + 0 + + wxString + wxFILTER_EXCLUDE_CHAR_LIST + wxTextValidator + m_labelText + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnEnterKey + + + + + + + 3 + wxEXPAND|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_VALUEMULTI + + 0 + + + + 0 + -1,60 + 1 + m_textLabelMultiLine + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_MULTILINE + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Size: + + 0 + + + 0 + + 1 + m_SizeTitle + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 1 + + + bSizeCtrlSizer + wxHORIZONTAL + none + + 3 + wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_SIZE + + 0 + + + + 0 + + 1 + m_TextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + units + + 0 + + + 0 + + 1 + m_staticSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + wxEXPAND|wxLEFT|wxRIGHT|wxTOP + 0 + + + m_OptionsSizer + wxHORIZONTAL + none + + 3 + wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Right" "Up" "Left" "Down" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + O&rientation + 1 + + 0 + + + 0 + + 1 + m_TextOrient + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxLEFT|wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Normal" "Italic" "Bold" "Bold Italic" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + St&yle + 1 + + 0 + + + 0 + + 1 + m_TextStyle + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxLEFT|wxTOP + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Input" "Output" "Bidirectional" "Tri-State" "Passive" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + S&hape + 1 + + 0 + + + 0 + + 1 + m_TextShape + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_edit_label_base.h b/eeschema/dialogs/dialog_edit_label_base.h new file mode 100644 index 00000000..2d22d1a4 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_label_base.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Feb 26 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EDIT_LABEL_BASE_H__ +#define __DIALOG_EDIT_LABEL_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LABEL_EDITOR_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LABEL_EDITOR_BASE : public DIALOG_SHIM +{ + private: + + protected: + enum + { + wxID_VALUESINGLE = 1000, + wxID_VALUEMULTI, + wxID_SIZE + }; + + wxFlexGridSizer* m_textControlSizer; + wxStaticText* m_staticText1; + wxTextCtrl* m_textLabelSingleLine; + wxTextCtrl* m_textLabelMultiLine; + wxStaticText* m_SizeTitle; + wxTextCtrl* m_TextSize; + wxStaticText* m_staticSizeUnits; + wxRadioBox* m_TextOrient; + wxRadioBox* m_TextStyle; + wxRadioBox* m_TextShape; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnEnterKey( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + wxString m_labelText; + + DIALOG_LABEL_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Text Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LABEL_EDITOR_BASE(); + +}; + +#endif //__DIALOG_EDIT_LABEL_BASE_H__ diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp new file mode 100644 index 00000000..ce101907 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp @@ -0,0 +1,796 @@ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011-2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2007-2016 KiCad Developers, see change_log.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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Local variables: +static int s_SelectedRow; + +#define COLUMN_FIELD_NAME 0 +#define COLUMN_TEXT 1 + +class DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB : public DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE +{ +public: + DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB( LIB_EDIT_FRAME* aParent, LIB_PART* aLibEntry ); + //~DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB() {} + +private: + // Events handlers: + void OnInitDialog( wxInitDialogEvent& event ); + void OnCloseDialog( wxCloseEvent& event ); + + void OnListItemDeselected( wxListEvent& event ); + void OnListItemSelected( wxListEvent& event ); + void addFieldButtonHandler( wxCommandEvent& event ); + + /** + * Function deleteFieldButtonHandler + * deletes a field. + * MANDATORY_FIELDS cannot be deleted. + * If a field is empty, it is removed. + * if not empty, the text is removed. + */ + void deleteFieldButtonHandler( wxCommandEvent& event ); + + void moveUpButtonHandler( wxCommandEvent& event ); + void OnCancelButtonClick( wxCommandEvent& event ); + void OnOKButtonClick( wxCommandEvent& event ); + void showButtonHandler( wxCommandEvent& event ); + + // internal functions: + void setSelectedFieldNdx( int aFieldNdx ); + + int getSelectedFieldNdx(); + + /** + * Function initBuffers + * sets up to edit the given component. + */ + void initBuffers(); + + /** + * Function findField + * searches m_FieldsBuf and returns a LIB_FIELD with \a aFieldName or NULL if + * not found. + */ + LIB_FIELD* findField( const wxString& aFieldName ); + + /** + * Function copySelectedFieldToPanel + * sets the values displayed on the panel according to + * the currently selected field row + */ + void copySelectedFieldToPanel(); + + /** + * Function copyPanelToSelectedField + * copies the values displayed on the panel fields to the currently selected field + * @return bool - true if all fields are OK, else false if the user has put + * bad data into a field, and this value can be used to deny a row change. + */ + bool copyPanelToSelectedField(); + + void setRowItem( int aFieldNdx, const wxString& aName, const wxString& aValue ); + void setRowItem( int aFieldNdx, const LIB_FIELD& aField ) + { + setRowItem( aFieldNdx, aField.GetName(), aField.GetText() ); + } + + /** + * Function updateDisplay + * update the listbox showing fields, according to the fields texts + * must be called after a text change in fields, if this change is not an edition + */ + void updateDisplay( ) + { + for( unsigned ii = MANDATORY_FIELDS; ii m_FieldsBuf; +}; + + +void LIB_EDIT_FRAME::InstallFieldsEditorDialog( wxCommandEvent& event ) +{ + if( !GetCurPart() ) + return; + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB dlg( this, GetCurPart() ); + + // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal + // frame. Therefore this dialog as a modal frame parent, MUST be run under + // quasimodal mode for the quasimodal frame support to work. So don't use + // the QUASIMODAL macros here. + if( dlg.ShowQuasiModal() != wxID_OK ) + return; + + UpdateAliasSelectList(); + UpdatePartSelectList(); + DisplayLibInfos(); + Refresh(); +} + + +DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB( + LIB_EDIT_FRAME* aParent, + LIB_PART* aLibEntry ) : + DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE( aParent ) +{ + m_parent = aParent; + m_libEntry = aLibEntry; + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnInitDialog( wxInitDialogEvent& event ) +{ + m_skipCopyFromPanel = false; + wxListItem columnLabel; + + columnLabel.SetImage( -1 ); + + columnLabel.SetText( _( "Name" ) ); + fieldListCtrl->InsertColumn( COLUMN_FIELD_NAME, columnLabel ); + + columnLabel.SetText( _( "Value" ) ); + fieldListCtrl->InsertColumn( COLUMN_TEXT, columnLabel ); + + m_staticTextUnitSize->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + m_staticTextUnitPosX->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + m_staticTextUnitPosY->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); + + initBuffers(); + copySelectedFieldToPanel(); + + stdDialogButtonSizerOK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnListItemDeselected( wxListEvent& event ) +{ + if( !m_skipCopyFromPanel ) + { + if( !copyPanelToSelectedField() ) + event.Skip(); // do not go to the next row + } +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnListItemSelected( wxListEvent& event ) +{ + // remember the selected row, statically + s_SelectedRow = event.GetIndex(); + + copySelectedFieldToPanel(); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnCancelButtonClick( wxCommandEvent& event ) +{ + EndQuasiModal( wxID_CANCEL ); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnCloseDialog( wxCloseEvent& event ) +{ + // On wxWidgets 2.8, and on Linux, call EndQuasiModal here is mandatory + // Otherwise, the main event loop is never restored, and Eeschema does not + // respond to any event, because the DIALOG_SHIM destructor is never called. + // on wxWidgets 3.0, or on Windows, the DIALOG_SHIM destructor is called, + // and calls EndQuasiModal. + // Therefore calling EndQuasiModal here is not mandatory but it creates no issues. + EndQuasiModal( wxID_CANCEL ); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnOKButtonClick( wxCommandEvent& event ) +{ + if( !copyPanelToSelectedField() ) + return; + + // test if reference prefix is acceptable + if( !SCH_COMPONENT::IsReferenceStringValid( m_FieldsBuf[REFERENCE].GetText() ) ) + { + DisplayError( NULL, _( "Illegal reference. References must start with a letter." ) ); + return; + } + + /* Note: this code is now (2010-dec-04) not used, because the value field is no more editable + * because changing the value is equivalent to create a new component or alias. + * This is now handled in libedit main frame, and no more in this dialog + * but this code is not removed, just in case + */ + /* If a new name entered in the VALUE field, that it not an existing alias name + * or root alias of the component */ + wxString newvalue = m_FieldsBuf[VALUE].GetText(); + + if( m_libEntry->HasAlias( newvalue ) && !m_libEntry->GetAlias( newvalue )->IsRoot() ) + { + wxString msg = wxString::Format( + _( "A new name is entered for this component\n" + "An alias %s already exists!\n" + "Cannot update this component" ), + GetChars( newvalue ) + ); + DisplayError( this, msg ); + return; + } + /* End unused code */ + + // save old cmp in undo list + m_parent->SaveCopyInUndoList( m_libEntry ); + + // delete any fields with no name or no value before we copy all of m_FieldsBuf + // back into the component + for( unsigned i = MANDATORY_FIELDS; i < m_FieldsBuf.size(); ) + { + if( m_FieldsBuf[i].GetName().IsEmpty() || m_FieldsBuf[i].GetText().IsEmpty() ) + { + m_FieldsBuf.erase( m_FieldsBuf.begin() + i ); + continue; + } + + ++i; + } + + // copy all the fields back, fully replacing any previous fields + m_libEntry->SetFields( m_FieldsBuf ); + + // We need to keep the name and the value the same at the moment! + SetName( m_libEntry->GetValueField().GetText() ); + + m_parent->OnModify(); + + EndQuasiModal( wxID_OK ); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::addFieldButtonHandler( wxCommandEvent& event ) +{ + // in case m_FieldsBuf[REFERENCE].m_Orient has changed on screen only, grab + // screen contents. + if( !copyPanelToSelectedField() ) + return; + + unsigned fieldNdx = m_FieldsBuf.size(); + + LIB_FIELD blank( fieldNdx ); + + m_FieldsBuf.push_back( blank ); + m_FieldsBuf[fieldNdx].SetName( TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldNdx ) ); + + setRowItem( fieldNdx, m_FieldsBuf[fieldNdx] ); + + m_skipCopyFromPanel = true; + setSelectedFieldNdx( fieldNdx ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::deleteFieldButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + if( fieldNdx < MANDATORY_FIELDS ) + { + wxBell(); + return; + } + + m_skipCopyFromPanel = true; + + if( m_FieldsBuf[fieldNdx].GetText().IsEmpty() ) + { + m_FieldsBuf.erase( m_FieldsBuf.begin() + fieldNdx ); + fieldListCtrl->DeleteItem( fieldNdx ); + + if( fieldNdx >= m_FieldsBuf.size() ) + --fieldNdx; + } + else + { + m_FieldsBuf[fieldNdx].Empty(); + copySelectedFieldToPanel(); + } + + updateDisplay( ); + + setRowItem( fieldNdx, m_FieldsBuf[fieldNdx] ); + setSelectedFieldNdx( fieldNdx ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB:: moveUpButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + // The first field which can be moved up is the second user field + // so any field which id <= MANDATORY_FIELDS cannot be moved up + if( fieldNdx <= MANDATORY_FIELDS ) + return; + + if( !copyPanelToSelectedField() ) + return; + + // swap the fieldNdx field with the one before it, in both the vector + // and in the fieldListCtrl + LIB_FIELD tmp = m_FieldsBuf[fieldNdx - 1]; + + m_FieldsBuf[fieldNdx - 1] = m_FieldsBuf[fieldNdx]; + setRowItem( fieldNdx - 1, m_FieldsBuf[fieldNdx] ); + m_FieldsBuf[fieldNdx - 1].SetId(fieldNdx - 1); + + m_FieldsBuf[fieldNdx] = tmp; + setRowItem( fieldNdx, tmp ); + m_FieldsBuf[fieldNdx].SetId(fieldNdx); + + updateDisplay( ); + + m_skipCopyFromPanel = true; + setSelectedFieldNdx( fieldNdx - 1 ); + m_skipCopyFromPanel = false; +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::showButtonHandler( wxCommandEvent& event ) +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx == DATASHEET ) + { + wxString datasheet_uri = fieldValueTextCtrl->GetValue(); + ::wxLaunchDefaultBrowser( datasheet_uri ); + } + else if( fieldNdx == FOOTPRINT ) + { + // pick a footprint using the footprint picker. + wxString fpid; + + KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true ); + + if( frame->ShowModal( &fpid, this ) ) + { + fieldValueTextCtrl->SetValue( fpid ); + setRowItem( fieldNdx, m_FieldsBuf[fieldNdx].GetName( false ), fpid ); + } + + frame->Destroy(); + } +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::setSelectedFieldNdx( int aFieldNdx ) +{ + // deselect old selection, but I think this is done by single selection + // flag within fieldListCtrl + // fieldListCtrl->SetItemState( s_SelectedRow, 0, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); + + if( aFieldNdx >= (int) m_FieldsBuf.size() ) + aFieldNdx = m_FieldsBuf.size() - 1; + + if( aFieldNdx < 0 ) + aFieldNdx = 0; + + fieldListCtrl->SetItemState( aFieldNdx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + fieldListCtrl->EnsureVisible( aFieldNdx ); + + s_SelectedRow = aFieldNdx; +} + + +int DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::getSelectedFieldNdx() +{ + return s_SelectedRow; +} + + +/** + * Function findfield + * searches a LIB_FIELD_LIST for aFieldName. + */ +static LIB_FIELD* findfield( const LIB_FIELDS& aList, const wxString& aFieldName ) +{ + const LIB_FIELD* field = NULL; + + for( unsigned i=0; iGetFields( cmpFields ); + + /* We have 3 component related field lists to be aware of: 1) UI + presentation (m_FieldsBuf), 2) fields in component ram copy, and 3) + fields recorded with component on disk. m_FieldsBuf is the list of UI + fields, and this list is not the same as the list which is in the + component, which is also not the same as the list on disk. All 3 lists + are potentially different. In the UI we choose to preserve the order of + the first MANDATORY_FIELDS which are sometimes called fixed fields. Then + we append the template fieldnames in the exact same order as the + template fieldname editor shows them. Then we append any user defined + fieldnames which came from the component, and user can modify it during + editing, but cannot delete or move a fixed field. + */ + + m_FieldsBuf.clear(); + + /* When this code was written, all field constructors ensured that the + MANDATORY_FIELDS are all present within a component (in ram only). So we can + knowingly copy them over in the normal order. Copy only the fixed fields + at first. Please do not break the field constructors. + */ + + // fixed fields: + for( int i=0; iGetTemplateFieldNames(); + + for( TEMPLATE_FIELDNAMES::const_iterator it = tfnames.begin(); it!=tfnames.end(); ++it ) + { + // add a new field unconditionally to the UI only for this template fieldname + + // field id must not be in range 0 - MANDATORY_FIELDS, set before saving to disk + LIB_FIELD fld( m_libEntry, -1 ); + + // See if field by same name already exists in component. + LIB_FIELD* libField = findfield( cmpFields, it->m_Name ); + + // If the field does not already exist in the component, then we + // use defaults from the template fieldname, otherwise the original + // values from the component will be set. + if( !libField ) + { + fld.SetName( it->m_Name ); + fld.SetText( it->m_Value ); // empty? ok too. + + if( !it->m_Visible ) + fld.SetVisible( false ); + else + fld.SetVisible( true ); + } + else + { + fld = *libField; // copy values from component, m_Name too + } + + m_FieldsBuf.push_back( fld ); + } + + // Lastly, append any original fields from the component which were not added + // from the set of fixed fields nor from the set of template fields. + for( unsigned i=MANDATORY_FIELDS; iGetName() ); + + if( !buf ) + { + m_FieldsBuf.push_back( *cmp ); + } + } + + /* field names have become more important than field ids, so we cannot + mangle the names in the buffer, but can do so in the panel, see elsewhere. + m_FieldsBuf[VALUE].m_Name << wxT( "/" ) << _( "Chip Name" ); + */ + + for( unsigned ii = 0; ii < m_FieldsBuf.size(); ++ii ) + { + setRowItem( ii, m_FieldsBuf[ii] ); + } + + // put focus on the list ctrl + fieldListCtrl->SetFocus(); + + // resume editing at the last row edited, last time dialog was up. + if ( s_SelectedRow < (int) m_FieldsBuf.size() ) + s_SelectedRow = 0; + + setSelectedFieldNdx( s_SelectedRow ); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::setRowItem( int aFieldNdx, const wxString& aName, const wxString& aValue ) +{ + wxASSERT( aFieldNdx >= 0 ); + + // insert blanks if aFieldNdx is referencing a "yet to be defined" row + while( aFieldNdx >= fieldListCtrl->GetItemCount() ) + { + long ndx = fieldListCtrl->InsertItem( fieldListCtrl->GetItemCount(), wxEmptyString ); + + wxASSERT( ndx >= 0 ); + + fieldListCtrl->SetItem( ndx, COLUMN_TEXT, wxEmptyString ); + } + + fieldListCtrl->SetItem( aFieldNdx, COLUMN_FIELD_NAME, aName ); + fieldListCtrl->SetItem( aFieldNdx, COLUMN_TEXT, aValue ); + + // recompute the column widths here, after setting texts + fieldListCtrl->SetColumnWidth( COLUMN_FIELD_NAME, wxLIST_AUTOSIZE ); + fieldListCtrl->SetColumnWidth( COLUMN_TEXT, wxLIST_AUTOSIZE ); +} + + +void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copySelectedFieldToPanel() +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return; + + LIB_FIELD& field = m_FieldsBuf[fieldNdx]; + + showCheckBox->SetValue( field.IsVisible() ); + + rotateCheckBox->SetValue( field.GetOrientation() == TEXT_ORIENT_VERT ); + + int style = 0; + + if( field.IsItalic() ) + style = 1; + + if( field.IsBold() ) + style |= 2; + + m_StyleRadioBox->SetSelection( style ); + + // Select the right text justification + if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT ) + m_FieldHJustifyCtrl->SetSelection(0); + else if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT ) + m_FieldHJustifyCtrl->SetSelection(2); + else + m_FieldHJustifyCtrl->SetSelection(1); + + if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM ) + m_FieldVJustifyCtrl->SetSelection(0); + else if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_TOP ) + m_FieldVJustifyCtrl->SetSelection(2); + else + m_FieldVJustifyCtrl->SetSelection(1); + + + // Field names have become more important than field ids, so we cannot + // mangle the names in the buffer but we can do so in the panel. + if( field.GetId() == VALUE ) + { + // This field is the lib name and the default value when loading this component in + // schematic. The value is now not editable here (in this dialog) because changing + // it is equivalent to create a new component or alias. This is handles in libedir, + // not in this dialog. + fieldNameTextCtrl->SetValue( field.GetName() + wxT( " / " ) + _( "Chip Name" ) ); + fieldValueTextCtrl->Enable( false ); + } + else + { + fieldValueTextCtrl->Enable( true ); + fieldNameTextCtrl->SetValue( field.GetName() ); + } + + // if fieldNdx == REFERENCE, VALUE, FOOTPRINT, or DATASHEET, then disable field name editing + fieldNameTextCtrl->Enable( fieldNdx >= MANDATORY_FIELDS ); + fieldNameTextCtrl->SetEditable( fieldNdx >= MANDATORY_FIELDS ); + + // only user defined fields may be moved, and not the top most user defined + // field since it would be moving up into the fixed fields, > not >= + moveUpButton->Enable( fieldNdx > MANDATORY_FIELDS ); + + // if fieldNdx == REFERENCE, VALUE, then disable delete button + deleteFieldButton->Enable( fieldNdx >= MANDATORY_FIELDS ); + + fieldValueTextCtrl->SetValidator( SCH_FIELD_VALIDATOR( true, field.GetId() ) ); + fieldValueTextCtrl->SetValue( field.GetText() ); + + textSizeTextCtrl->SetValue( EDA_GRAPHIC_TEXT_CTRL::FormatSize( g_UserUnit, field.GetSize().x ) ); + + m_show_datasheet_button->Enable( fieldNdx == DATASHEET || fieldNdx == FOOTPRINT ); + + if( fieldNdx == DATASHEET ) + m_show_datasheet_button->SetLabel( _( "Show in Browser" ) ); + else if( fieldNdx == FOOTPRINT ) + m_show_datasheet_button->SetLabel( _( "Assign Footprint" ) ); + else + m_show_datasheet_button->SetLabel( wxEmptyString ); + + wxPoint coord = field.GetTextPosition(); + wxPoint zero; + + // If the field value is empty and the position is at relative zero, we set the + // initial position as a small offset from the ref field, and orient + // it the same as the ref field. That is likely to put it at least + // close to the desired position. + if( coord == zero && field.GetText().IsEmpty() ) + { + rotateCheckBox->SetValue( m_FieldsBuf[REFERENCE].GetOrientation() == TEXT_ORIENT_VERT ); + + coord.x = m_FieldsBuf[REFERENCE].GetTextPosition().x + + (fieldNdx - MANDATORY_FIELDS + 1) * 100; + coord.y = m_FieldsBuf[REFERENCE].GetTextPosition().y + + (fieldNdx - MANDATORY_FIELDS + 1) * 100; + + // coord can compute negative if field is < MANDATORY_FIELDS, e.g. FOOTPRINT. + // That is ok, we basically don't want all the new empty fields on + // top of each other. + } + + wxString coordText = StringFromValue( g_UserUnit, coord.x ); + posXTextCtrl->SetValue( coordText ); + + // Note: the Y axis for components in lib is from bottom to top + // and the screen axis is top to bottom: we must change the y coord sign for editing + coord.y = -coord.y; + coordText = StringFromValue( g_UserUnit, coord.y ); + posYTextCtrl->SetValue( coordText ); +} + + +bool DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copyPanelToSelectedField() +{ + unsigned fieldNdx = getSelectedFieldNdx(); + + if( fieldNdx >= m_FieldsBuf.size() ) // traps the -1 case too + return true; + + // Check for illegal field text. + if( fieldValueTextCtrl->GetValidator() + && !fieldValueTextCtrl->GetValidator()->Validate( this ) ) + return false; + + LIB_FIELD& field = m_FieldsBuf[fieldNdx]; + + if( showCheckBox->GetValue() ) + field.SetVisible( true ); + else + field.SetVisible( false ); + + if( rotateCheckBox->GetValue() ) + field.SetOrientation( TEXT_ORIENT_VERT ); + else + field.SetOrientation( TEXT_ORIENT_HORIZ ); + + // Copy the text justification + static const EDA_TEXT_HJUSTIFY_T hjustify[3] = { + GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_HJUSTIFY_RIGHT + }; + + static const EDA_TEXT_VJUSTIFY_T vjustify[3] = { + GR_TEXT_VJUSTIFY_BOTTOM, GR_TEXT_VJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP + }; + + field.SetHorizJustify( hjustify[m_FieldHJustifyCtrl->GetSelection()] ); + field.SetVertJustify( vjustify[m_FieldVJustifyCtrl->GetSelection()] ); + + // Blank/empty field texts for REFERENCE and VALUE are not allowed. + // (Value is the name of the component in lib!) + // Change them only if user provided a non blank value + if( !fieldValueTextCtrl->GetValue().IsEmpty() || fieldNdx > VALUE ) + field.SetText( fieldValueTextCtrl->GetValue() ); + + // FieldNameTextCtrl has a tricked value in it for VALUE index, do not copy it back. + // It has the "Chip Name" appended. + if( field.GetId() >= MANDATORY_FIELDS ) + { + wxString name = fieldNameTextCtrl->GetValue(); + field.SetName( name ); + } + + setRowItem( fieldNdx, field ); // update fieldListCtrl + + int tmp = EDA_GRAPHIC_TEXT_CTRL::ParseSize( textSizeTextCtrl->GetValue(), g_UserUnit ); + + field.SetSize( wxSize( tmp, tmp ) ); + + int style = m_StyleRadioBox->GetSelection(); + + field.SetItalic( (style & 1 ) != 0 ); + field.SetBold( (style & 2 ) != 0 ); + + wxPoint pos( ValueFromString( g_UserUnit, posXTextCtrl->GetValue() ), + ValueFromString( g_UserUnit, posYTextCtrl->GetValue() ) ); + + // Note: the Y axis for components in lib is from bottom to top + // and the screen axis is top to bottom: we must change the y coord sign for editing + pos.y = -pos.y; + + field.SetTextPosition( pos ); + + return true; +} diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.cpp b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.cpp new file mode 100644 index 00000000..8bdc8b5c --- /dev/null +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.cpp @@ -0,0 +1,229 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_edit_libentry_fields_in_lib_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerFieldsSetup; + bSizerFieldsSetup = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizerFiledsList; + bSizerFiledsList = new wxBoxSizer( wxVERTICAL ); + + fieldListCtrl = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES ); + bSizerFiledsList->Add( fieldListCtrl, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 6 ); + + addFieldButton = new wxButton( this, wxID_ANY, _("Add Field"), wxDefaultPosition, wxDefaultSize, 0 ); + addFieldButton->SetToolTip( _("Add a new custom field") ); + + bSizerFiledsList->Add( addFieldButton, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + deleteFieldButton = new wxButton( this, wxID_ANY, _("Delete Field"), wxDefaultPosition, wxDefaultSize, 0 ); + deleteFieldButton->SetToolTip( _("Delete one of the optional fields") ); + + bSizerFiledsList->Add( deleteFieldButton, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + moveUpButton = new wxButton( this, wxID_ANY, _("Move Up"), wxDefaultPosition, wxDefaultSize, 0 ); + moveUpButton->SetToolTip( _("Move the selected optional fields up one position") ); + + bSizerFiledsList->Add( moveUpButton, 0, wxALL|wxEXPAND, 5 ); + + + bSizerFieldsSetup->Add( bSizerFiledsList, 3, wxEXPAND, 5 ); + + wxBoxSizer* fieldEditBoxSizer; + fieldEditBoxSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerJustify; + bSizerJustify = new wxBoxSizer( wxHORIZONTAL ); + + wxString m_FieldHJustifyCtrlChoices[] = { _("Left"), _("Center"), _("Right") }; + int m_FieldHJustifyCtrlNChoices = sizeof( m_FieldHJustifyCtrlChoices ) / sizeof( wxString ); + m_FieldHJustifyCtrl = new wxRadioBox( this, wxID_ANY, _("Horiz. Justify"), wxDefaultPosition, wxDefaultSize, m_FieldHJustifyCtrlNChoices, m_FieldHJustifyCtrlChoices, 1, wxRA_SPECIFY_COLS ); + m_FieldHJustifyCtrl->SetSelection( 1 ); + m_FieldHJustifyCtrl->SetToolTip( _("Select if the component is to be rotated when drawn") ); + + bSizerJustify->Add( m_FieldHJustifyCtrl, 1, wxEXPAND|wxALL, 5 ); + + wxString m_FieldVJustifyCtrlChoices[] = { _("Bottom"), _("Center"), _("Top") }; + int m_FieldVJustifyCtrlNChoices = sizeof( m_FieldVJustifyCtrlChoices ) / sizeof( wxString ); + m_FieldVJustifyCtrl = new wxRadioBox( this, wxID_ANY, _("Vert. Justify"), wxDefaultPosition, wxDefaultSize, m_FieldVJustifyCtrlNChoices, m_FieldVJustifyCtrlChoices, 1, wxRA_SPECIFY_COLS ); + m_FieldVJustifyCtrl->SetSelection( 0 ); + m_FieldVJustifyCtrl->SetToolTip( _("Pick the graphical transformation to be used when displaying the component, if any") ); + + bSizerJustify->Add( m_FieldVJustifyCtrl, 1, wxEXPAND|wxALL, 5 ); + + + fieldEditBoxSizer->Add( bSizerJustify, 1, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bSizerAspect; + bSizerAspect = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticBoxSizer* visibilitySizer; + visibilitySizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Visibility") ), wxVERTICAL ); + + showCheckBox = new wxCheckBox( this, wxID_ANY, _("Show"), wxDefaultPosition, wxDefaultSize, 0 ); + showCheckBox->SetToolTip( _("Check if you want this field visible") ); + + visibilitySizer->Add( showCheckBox, 0, wxALL, 5 ); + + rotateCheckBox = new wxCheckBox( this, wxID_ANY, _("Rotate"), wxDefaultPosition, wxDefaultSize, 0 ); + rotateCheckBox->SetToolTip( _("Check if you want this field's text rotated 90 degrees") ); + + visibilitySizer->Add( rotateCheckBox, 0, wxALL, 5 ); + + + bSizerAspect->Add( visibilitySizer, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxString m_StyleRadioBoxChoices[] = { _("Normal"), _("Italic"), _("Bold"), _("Bold Italic") }; + int m_StyleRadioBoxNChoices = sizeof( m_StyleRadioBoxChoices ) / sizeof( wxString ); + m_StyleRadioBox = new wxRadioBox( this, wxID_ANY, _("Style:"), wxDefaultPosition, wxDefaultSize, m_StyleRadioBoxNChoices, m_StyleRadioBoxChoices, 1, wxRA_SPECIFY_COLS ); + m_StyleRadioBox->SetSelection( 0 ); + bSizerAspect->Add( m_StyleRadioBox, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + + fieldEditBoxSizer->Add( bSizerAspect, 1, wxALL|wxEXPAND|wxTOP, 5 ); + + wxBoxSizer* fieldNameBoxSizer; + fieldNameBoxSizer = new wxBoxSizer( wxVERTICAL ); + + fieldNameLabel = new wxStaticText( this, wxID_ANY, _("Field Name"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldNameLabel->Wrap( -1 ); + fieldNameBoxSizer->Add( fieldNameLabel, 0, 0, 5 ); + + fieldNameTextCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fieldNameTextCtrl->SetMaxLength( 0 ); + fieldNameTextCtrl->SetToolTip( _("The text (or value) of the currently selected field") ); + + fieldNameBoxSizer->Add( fieldNameTextCtrl, 0, wxBOTTOM|wxEXPAND, 5 ); + + fieldValueLabel = new wxStaticText( this, wxID_ANY, _("Field Value"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldValueLabel->Wrap( -1 ); + fieldNameBoxSizer->Add( fieldValueLabel, 0, wxTOP, 5 ); + + fieldValueTextCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fieldValueTextCtrl->SetMaxLength( 0 ); + fieldValueTextCtrl->SetToolTip( _("The text (or value) of the currently selected field") ); + + fieldNameBoxSizer->Add( fieldValueTextCtrl, 0, wxBOTTOM|wxEXPAND, 5 ); + + m_show_datasheet_button = new wxButton( this, wxID_ANY, _("Show in Browser"), wxDefaultPosition, wxDefaultSize, 0 ); + m_show_datasheet_button->SetToolTip( _("If your datasheet is given as an http:// link, then pressing this button should bring it up in your webbrowser.") ); + + fieldNameBoxSizer->Add( m_show_datasheet_button, 0, wxBOTTOM|wxEXPAND|wxTOP, 5 ); + + + fieldEditBoxSizer->Add( fieldNameBoxSizer, 0, wxALL|wxEXPAND, 5 ); + + wxFlexGridSizer* fgSizerPosSize; + fgSizerPosSize = new wxFlexGridSizer( 3, 3, 5, 5 ); + fgSizerPosSize->AddGrowableCol( 1 ); + fgSizerPosSize->SetFlexibleDirection( wxBOTH ); + fgSizerPosSize->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + textSizeLabel = new wxStaticText( this, wxID_ANY, _("Size"), wxDefaultPosition, wxDefaultSize, 0 ); + textSizeLabel->Wrap( -1 ); + fgSizerPosSize->Add( textSizeLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + textSizeTextCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + textSizeTextCtrl->SetMaxLength( 0 ); + textSizeTextCtrl->SetToolTip( _("The vertical height of the currently selected field's text in the schematic") ); + + fgSizerPosSize->Add( textSizeTextCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_staticTextUnitSize = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitSize->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitSize, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posXLabel = new wxStaticText( this, wxID_ANY, _("X Position"), wxDefaultPosition, wxDefaultSize, 0 ); + posXLabel->Wrap( -1 ); + fgSizerPosSize->Add( posXLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posXTextCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + posXTextCtrl->SetMaxLength( 0 ); + fgSizerPosSize->Add( posXTextCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_staticTextUnitPosX = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitPosX->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitPosX, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posYLabel = new wxStaticText( this, wxID_ANY, _("Y Position"), wxDefaultPosition, wxDefaultSize, 0 ); + posYLabel->Wrap( -1 ); + fgSizerPosSize->Add( posYLabel, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + posYTextCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + posYTextCtrl->SetMaxLength( 0 ); + posYTextCtrl->SetToolTip( _("The Y coordinate of the text relative to the component") ); + + fgSizerPosSize->Add( posYTextCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_staticTextUnitPosY = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUnitPosY->Wrap( -1 ); + fgSizerPosSize->Add( m_staticTextUnitPosY, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + fieldEditBoxSizer->Add( fgSizerPosSize, 1, wxALL|wxEXPAND, 5 ); + + + bSizerFieldsSetup->Add( fieldEditBoxSizer, 2, wxEXPAND, 5 ); + + + mainSizer->Add( bSizerFieldsSetup, 1, wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + mainSizer->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + stdDialogButtonSizer = new wxStdDialogButtonSizer(); + stdDialogButtonSizerOK = new wxButton( this, wxID_OK ); + stdDialogButtonSizer->AddButton( stdDialogButtonSizerOK ); + stdDialogButtonSizerCancel = new wxButton( this, wxID_CANCEL ); + stdDialogButtonSizer->AddButton( stdDialogButtonSizerCancel ); + stdDialogButtonSizer->Realize(); + + mainSizer->Add( stdDialogButtonSizer, 0, wxALL|wxEXPAND, 6 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + mainSizer->Fit( this ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnCloseDialog ) ); + this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnInitDialog ) ); + fieldListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnListItemDeselected ), NULL, this ); + fieldListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnListItemSelected ), NULL, this ); + addFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::addFieldButtonHandler ), NULL, this ); + deleteFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::deleteFieldButtonHandler ), NULL, this ); + moveUpButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::moveUpButtonHandler ), NULL, this ); + m_show_datasheet_button->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::showButtonHandler ), NULL, this ); + stdDialogButtonSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnCancelButtonClick ), NULL, this ); + stdDialogButtonSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnOKButtonClick ), NULL, this ); +} + +DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::~DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnCloseDialog ) ); + this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnInitDialog ) ); + fieldListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnListItemDeselected ), NULL, this ); + fieldListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnListItemSelected ), NULL, this ); + addFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::addFieldButtonHandler ), NULL, this ); + deleteFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::deleteFieldButtonHandler ), NULL, this ); + moveUpButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::moveUpButtonHandler ), NULL, this ); + m_show_datasheet_button->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::showButtonHandler ), NULL, this ); + stdDialogButtonSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnCancelButtonClick ), NULL, this ); + stdDialogButtonSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE::OnOKButtonClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.fbp b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.fbp new file mode 100644 index 00000000..42a647e7 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.fbp @@ -0,0 +1,2326 @@ + + + + + ; + C++ + 1 + source_name + 0 + 0 + res + ANSI + connect + dialog_edit_libentry_fields_in_lib_base + 1000 + none + 1 + DialogEditLibentryFields_in_lib_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE + + -1,-1 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU + DIALOG_SHIM; dialog_shim.h + Field Properties + + + + + + + + + + + + + + OnCloseDialog + + + + + + OnInitDialog + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizerFieldsSetup + wxHORIZONTAL + none + + 5 + wxEXPAND + 3 + + + bSizerFiledsList + wxVERTICAL + none + + 6 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + -1,-1 + 1 + fieldListCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemDeselected + + + + OnListItemSelected + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Add Field + + 0 + + + 0 + + 1 + addFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a new custom field + + wxFILTER_NONE + wxDefaultValidator + + + + + addFieldButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Delete Field + + 0 + + + 0 + + 1 + deleteFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Delete one of the optional fields + + wxFILTER_NONE + wxDefaultValidator + + + + + deleteFieldButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Move Up + + 0 + + + 0 + + 1 + moveUpButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the selected optional fields up one position + + wxFILTER_NONE + wxDefaultValidator + + + + + moveUpButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 2 + + + fieldEditBoxSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + bSizerJustify + wxHORIZONTAL + none + + 5 + wxEXPAND|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Left" "Center" "Right" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Horiz. Justify + 1 + + 0 + + + 0 + + 1 + m_FieldHJustifyCtrl + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + Select if the component is to be rotated when drawn + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Bottom" "Center" "Top" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Vert. Justify + 1 + + 0 + + + 0 + + 1 + m_FieldVJustifyCtrl + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + Pick the graphical transformation to be used when displaying the component, if any + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxTOP + 1 + + + bSizerAspect + wxHORIZONTAL + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + wxID_ANY + Visibility + + visibilitySizer + wxVERTICAL + none + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show + + 0 + + + 0 + + 1 + showCheckBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check if you want this field visible + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Rotate + + 0 + + + 0 + + 1 + rotateCheckBox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Check if you want this field's text rotated 90 degrees + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Normal" "Italic" "Bold" "Bold Italic" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Style: + 1 + + 0 + + + 0 + + 1 + m_StyleRadioBox + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + + fieldNameBoxSizer + wxVERTICAL + none + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Field Name + + 0 + + + 0 + + 1 + fieldNameLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldNameTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The text (or value) of the currently selected field + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Field Value + + 0 + + + 0 + + 1 + fieldValueLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldValueTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The text (or value) of the currently selected field + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show in Browser + + 0 + + + 0 + + 1 + m_show_datasheet_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + If your datasheet is given as an http:// link, then pressing this button should bring it up in your webbrowser. + + wxFILTER_NONE + wxDefaultValidator + + + + + showButtonHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 3 + wxBOTH + 1 + + 5 + + fgSizerPosSize + wxFLEX_GROWMODE_SPECIFIED + none + 3 + 5 + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size + + 0 + + + 0 + + 1 + textSizeLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + textSizeTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The vertical height of the currently selected field's text in the schematic + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + X Position + + 0 + + + 0 + + 1 + posXLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + posXTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitPosX + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Y Position + + 0 + + + 0 + + 1 + posYLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + posYTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + The Y coordinate of the text relative to the component + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextUnitPosY + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + stdDialogButtonSizer + protected + + OnCancelButtonClick + + + + OnOKButtonClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.h b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.h new file mode 100644 index 00000000..002e7279 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib_base.h @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE_H__ +#define __DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxListCtrl* fieldListCtrl; + wxButton* addFieldButton; + wxButton* deleteFieldButton; + wxButton* moveUpButton; + wxRadioBox* m_FieldHJustifyCtrl; + wxRadioBox* m_FieldVJustifyCtrl; + wxCheckBox* showCheckBox; + wxCheckBox* rotateCheckBox; + wxRadioBox* m_StyleRadioBox; + wxStaticText* fieldNameLabel; + wxTextCtrl* fieldNameTextCtrl; + wxStaticText* fieldValueLabel; + wxTextCtrl* fieldValueTextCtrl; + wxButton* m_show_datasheet_button; + wxStaticText* textSizeLabel; + wxTextCtrl* textSizeTextCtrl; + wxStaticText* m_staticTextUnitSize; + wxStaticText* posXLabel; + wxTextCtrl* posXTextCtrl; + wxStaticText* m_staticTextUnitPosX; + wxStaticText* posYLabel; + wxTextCtrl* posYTextCtrl; + wxStaticText* m_staticTextUnitPosY; + wxStaticLine* m_staticline1; + wxStdDialogButtonSizer* stdDialogButtonSizer; + wxButton* stdDialogButtonSizerOK; + wxButton* stdDialogButtonSizerCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); } + virtual void OnInitDialog( wxInitDialogEvent& event ) { event.Skip(); } + virtual void OnListItemDeselected( wxListEvent& event ) { event.Skip(); } + virtual void OnListItemSelected( wxListEvent& event ) { event.Skip(); } + virtual void addFieldButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void deleteFieldButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void moveUpButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void showButtonHandler( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Field Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU ); + ~DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE(); + +}; + +#endif //__DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE_H__ diff --git a/eeschema/dialogs/dialog_edit_one_field.cpp b/eeschema/dialogs/dialog_edit_one_field.cpp new file mode 100644 index 00000000..3ee5f1e8 --- /dev/null +++ b/eeschema/dialogs/dialog_edit_one_field.cpp @@ -0,0 +1,278 @@ +/** + * @file dialog_edit_one_field.cpp + * @brief dialog to editing a field ( not a graphic text) in current component. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com + * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +// These should probably moved into some other file as helpers. +EDA_TEXT_HJUSTIFY_T IntToEdaTextHorizJustify( int aHorizJustify ) +{ + wxASSERT( aHorizJustify >= GR_TEXT_HJUSTIFY_LEFT && aHorizJustify <= GR_TEXT_HJUSTIFY_RIGHT ); + + if( aHorizJustify > GR_TEXT_HJUSTIFY_RIGHT ) + return GR_TEXT_HJUSTIFY_RIGHT; + + if( aHorizJustify < GR_TEXT_HJUSTIFY_LEFT ) + return GR_TEXT_HJUSTIFY_LEFT; + + return (EDA_TEXT_HJUSTIFY_T) aHorizJustify; +} + + +EDA_TEXT_VJUSTIFY_T IntToEdaTextVertJustify( int aVertJustify ) +{ + wxASSERT( aVertJustify >= GR_TEXT_VJUSTIFY_TOP && aVertJustify <= GR_TEXT_VJUSTIFY_BOTTOM ); + + if( aVertJustify > GR_TEXT_VJUSTIFY_BOTTOM ) + return GR_TEXT_VJUSTIFY_BOTTOM; + + if( aVertJustify < GR_TEXT_VJUSTIFY_TOP ) + return GR_TEXT_VJUSTIFY_TOP; + + return (EDA_TEXT_VJUSTIFY_T) aVertJustify; +} + + +DIALOG_EDIT_ONE_FIELD::DIALOG_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, const wxString& aTitle, + const EDA_TEXT* aTextItem ) : + DIALOG_LIB_EDIT_TEXT_BASE( aParent ) +{ + SetTitle( aTitle ); + + // The field ID and power status are Initialized in the derived object's ctor. + m_fieldId = VALUE; + m_isPower = false; + + m_text = aTextItem->GetText(); + m_style = aTextItem->IsItalic() ? 1 : 0; + m_style += aTextItem->IsBold() ? 2 : 0; + m_size = aTextItem->GetSize().x; + m_orientation = ( aTextItem->GetOrientation() == TEXT_ORIENT_VERT ); + m_verticalJustification = aTextItem->GetVertJustify() + 1; + m_horizontalJustification = aTextItem->GetHorizJustify() + 1; + m_isVisible = aTextItem->IsVisible(); +} + + +void DIALOG_EDIT_ONE_FIELD::init() +{ + wxString msg; + + m_TextValue->SetFocus(); + SCH_BASE_FRAME* parent = static_cast( GetParent() ); + m_TextValue->SetValidator( SCH_FIELD_VALIDATOR( + parent->IsType( FRAME_SCH_LIB_EDITOR ), + m_fieldId, &m_text ) ); + + // Disable options for graphic text editing which are not needed for fields. + m_CommonConvert->Show( false ); + m_CommonUnit->Show( false ); + + // Show the footprint selection dialog if this is the footprint field. + if( m_fieldId == FOOTPRINT ) + { + m_TextValueSelectButton->Show(); + m_TextValueSelectButton->Enable(); + } + else + { + m_TextValueSelectButton->Hide(); + m_TextValueSelectButton->Disable(); + } + + msg = m_TextSizeText->GetLabel() + ReturnUnitSymbol(); + m_TextSizeText->SetLabel( msg ); + + + // Value fields of power components cannot be modified. This will grey out + // the text box and display an explanation. + if( m_fieldId == VALUE && m_isPower ) + { + m_PowerComponentValues->Show( true ); + m_TextValue->Enable( false ); + } + else + { + m_PowerComponentValues->Show( false ); + m_TextValue->Enable( true ); + } + + m_sdbSizerButtonsOK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_EDIT_ONE_FIELD::OnTextValueSelectButtonClick( wxCommandEvent& aEvent ) +{ + // pick a footprint using the footprint picker. + wxString fpid; + + KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true ); + + if( frame->ShowModal( &fpid, this ) ) + { + m_TextValue->SetValue( fpid ); + } + + frame->Destroy(); +} + + +bool DIALOG_EDIT_ONE_FIELD::TransferDataToWindow() +{ + wxLogDebug( "In DIALOG_EDIT_ONE_FIELD::TransferDataToWindow()" ); + + m_TextValue->SetValue( m_text ); + m_Orient->SetValue( m_orientation ); + m_TextSize->SetValue( StringFromValue( g_UserUnit, m_size ) ); + m_TextHJustificationOpt->SetSelection( m_horizontalJustification ); + m_TextVJustificationOpt->SetSelection( m_verticalJustification ); + m_Invisible->SetValue( !m_isVisible ); + m_TextShapeOpt->SetSelection( m_style ); + + return true; +} + + +bool DIALOG_EDIT_ONE_FIELD::TransferDataFromWindow() +{ + wxLogDebug( "In DIALOG_EDIT_ONE_FIELD::TransferDataFromWindow()" ); + + m_text = m_TextValue->GetValue(); + + // There are lots of specific tests required to validate field text. + if( m_fieldId == REFERENCE ) + { + // Test if the reference string is valid: + if( !SCH_COMPONENT::IsReferenceStringValid( m_text ) ) + { + DisplayError( this, _( "Illegal reference field value!" ) ); + return false; + } + } + + m_orientation = m_Orient->GetValue(); + m_size = ValueFromString( g_UserUnit, m_TextSize->GetValue() ); + m_horizontalJustification = m_TextHJustificationOpt->GetSelection(); + m_verticalJustification = m_TextVJustificationOpt->GetSelection(); + m_isVisible = !m_Invisible->GetValue(); + m_style = m_TextShapeOpt->GetSelection(); + + return true; +} + + +void DIALOG_EDIT_ONE_FIELD::updateText( EDA_TEXT* aText ) +{ + aText->SetSize( wxSize( m_size, m_size ) ); + aText->SetVisible( m_isVisible ); + aText->SetOrientation( m_orientation ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ ); + aText->SetItalic( (m_style & 1) != 0 ); + aText->SetBold( (m_style & 2) != 0 ); + aText->SetHorizJustify( IntToEdaTextHorizJustify( m_horizontalJustification - 1 ) ); + aText->SetVertJustify( IntToEdaTextVertJustify( m_verticalJustification - 1 ) ); +} + + +DIALOG_LIB_EDIT_ONE_FIELD::DIALOG_LIB_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, + const wxString& aTitle, + const LIB_FIELD* aField ) : + DIALOG_EDIT_ONE_FIELD( aParent, aTitle, dynamic_cast< const EDA_TEXT* >( aField ) ) +{ + m_fieldId = aField->GetId(); + + // When in the library editor, power components can be renamed. + m_isPower = false; + init(); +} + + +DIALOG_SCH_EDIT_ONE_FIELD::DIALOG_SCH_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, + const wxString& aTitle, + const SCH_FIELD* aField ) : + DIALOG_EDIT_ONE_FIELD( aParent, aTitle, dynamic_cast< const EDA_TEXT* >( aField ) ) +{ + m_fieldId = aField->GetId(); + + const SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent(); + + wxASSERT_MSG( component != NULL && component->Type() == SCH_COMPONENT_T, + wxT( "Invalid schematic field parent item." ) ); + + const LIB_PART* part = GetParent()->Prj().SchLibs()->FindLibPart( component->GetPartName() ); + + wxASSERT_MSG( part, wxT( "Library part for component <" ) + + component->GetPartName() + wxT( "> could not be found." ) ); + + m_isPower = part->IsPower(); + + init(); +} + + +void DIALOG_SCH_EDIT_ONE_FIELD::UpdateField( SCH_FIELD* aField, SCH_SHEET_PATH* aSheetPath ) +{ + wxASSERT( aField != NULL || aField->Type() != SCH_FIELD_T ); + + if( aField->GetId() == REFERENCE ) + { + wxASSERT( aSheetPath != NULL ); + + SCH_COMPONENT* component = dynamic_cast< SCH_COMPONENT* >( aField->GetParent() ); + + wxASSERT( component != NULL ); + + if( component != NULL ) + component->SetRef( aSheetPath, m_text ); + } + + aField->SetText( m_text ); + updateText( aField ); +} diff --git a/eeschema/dialogs/dialog_edit_one_field.h b/eeschema/dialogs/dialog_edit_one_field.h new file mode 100644 index 00000000..d12e47ba --- /dev/null +++ b/eeschema/dialogs/dialog_edit_one_field.h @@ -0,0 +1,159 @@ + +#ifndef DIALOG_EDIT_ONE_FIELD_H_ +#define DIALOG_EDIT_ONE_FIELD_H_ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com + * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 + +class SCH_BASE_FRAME; +class LIB_FIELD; +class SCH_FIELD; +class EDA_TEXT; + + +/** + * Class DIALOG_EDIT_ONE_FIELD + * is a base class to edit schematic and component library fields. + *

      + * This class is setup in expectation of its children + * possibly using Kiway player so ShowQuasiModal is required when calling + * any subclasses. + *

      + */ +class DIALOG_EDIT_ONE_FIELD : public DIALOG_LIB_EDIT_TEXT_BASE +{ +public: + DIALOG_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, const wxString& aTitle, + const EDA_TEXT* aTextItem ); + + ~DIALOG_EDIT_ONE_FIELD() {} + + virtual bool TransferDataToWindow(); + + virtual bool TransferDataFromWindow(); + + SCH_BASE_FRAME* GetParent() { return dynamic_cast< SCH_BASE_FRAME* >( wxDialog::GetParent() ); } + + const wxString& GetText() const { return m_text; } + +protected: + + void init(); + + void updateText( EDA_TEXT* aText ); + + /** + * Function OnTextValueSelectButtonClick + * Handles the select button next to the text value field. The current assumption + * is that this event will only be enabled for footprint type fields. In the future + * this function may need to be moved to the subclasses to access m_field and check for + * the field type if more select actions are desired. + * + * @param aEvent is the the wX event thrown when the button is clicked, this isn't used + */ + void OnTextValueSelectButtonClick( wxCommandEvent& aEvent ); + + /// @todo Update DIALOG_SHIM to handle this transparently so no matter what mode the + /// dialogs is shown, everything is handled without this ugliness. + void OnOkClick( wxCommandEvent& aEvent ) + { + if( IsQuasiModal() ) + EndQuasiModal( wxID_OK ); + else + EndDialog( wxID_OK ); + } + + void OnCancelClick( wxCommandEvent& event ) + { + if( IsQuasiModal() ) + EndQuasiModal( wxID_CANCEL ); + else + EndDialog( wxID_CANCEL ); + } + + void OnCloseDialog( wxCloseEvent& aEvent ) + { + if( IsQuasiModal() ) + EndQuasiModal( wxID_CANCEL ); + else + EndDialog( wxID_CANCEL ); + } + + int m_fieldId; + bool m_isPower; + wxString m_text; + int m_style; + int m_size; + bool m_orientation; + int m_verticalJustification; + int m_horizontalJustification; + bool m_isVisible; +}; + + +/** + * Class DIALOG_LIB_EDIT_ONE_FIELD + * is a the class to handle editing a single component field in the library editor. + *

      + * @note Use ShowQuasiModal when calling this class! + *

      + */ +class DIALOG_LIB_EDIT_ONE_FIELD : public DIALOG_EDIT_ONE_FIELD +{ +public: + DIALOG_LIB_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, const wxString& aTitle, + const LIB_FIELD* aField ); + + ~DIALOG_LIB_EDIT_ONE_FIELD() {} + + void UpdateField( LIB_FIELD* aField ) + { + aField->SetText( m_text ); + updateText( aField ); + } +}; + + +/** + * Class DIALOG_SCH_EDIT_ONE_FIELD + * is a the class to handle editing a single component field in the schematic editor. + *

      + * @note Use ShowQuasiModal when calling this class! + *

      + */ +class DIALOG_SCH_EDIT_ONE_FIELD : public DIALOG_EDIT_ONE_FIELD +{ +public: + DIALOG_SCH_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent, const wxString& aTitle, + const SCH_FIELD* aField ); + + ~DIALOG_SCH_EDIT_ONE_FIELD() {} + + void UpdateField( SCH_FIELD* aField, SCH_SHEET_PATH* aSheetPath ); +}; + +#endif // DIALOG_EDIT_ONE_FIELD_H_ diff --git a/eeschema/dialogs/dialog_eeschema_config.cpp b/eeschema/dialogs/dialog_eeschema_config.cpp new file mode 100644 index 00000000..07dab497 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_config.cpp @@ -0,0 +1,490 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2006-2013 KiCad Developers, see change_log.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 + */ + +/** + * @file dialog_eeschema_config.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +class SCH_EDIT_FRAME; +class EDA_DRAW_FRAME; + + +class DIALOG_EESCHEMA_CONFIG : public DIALOG_EESCHEMA_CONFIG_FBP +{ +public: + DIALOG_EESCHEMA_CONFIG( wxWindow* aParent, + wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames ); + +private: + wxConfigBase* m_config; + wxString* m_callers_project_specific_lib_paths; + wxArrayString* m_callers_lib_names; + + bool m_lib_list_changed; + bool m_lib_path_changed; + + //------ event handlers, overiding the fbp handlers -------------- + + void OnCloseWindow( wxCloseEvent& event ); + + /* Remove a library to the library list. + * The real list (m_Parent->m_ComponentLibFiles) is not changed, so the change can be canceled + */ + void OnRemoveLibClick( wxCommandEvent& event ); + + /* Insert or add a library to the library list: + * The new library is put in list before (insert button) the selection, + * or added (add button) to end of list + * The real list (m_Parent->m_ComponentLibFiles) is not changed, so the change + * can be canceled + */ + void OnAddOrInsertLibClick( wxCommandEvent& event ); + + void OnAddOrInsertPath( wxCommandEvent& event ); + void OnOkClick( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); + void OnRemoveUserPath( wxCommandEvent& event ); + void OnButtonUpClick( wxCommandEvent& event ); + void OnButtonDownClick( wxCommandEvent& event ); +}; + + +DIALOG_EESCHEMA_CONFIG::DIALOG_EESCHEMA_CONFIG( wxWindow* aParent, + wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames ) : + DIALOG_EESCHEMA_CONFIG_FBP( aParent ), + m_callers_project_specific_lib_paths( aCallersProjectSpecificLibPaths ), + m_callers_lib_names( aCallersLibNames ), + m_lib_list_changed( false ), + m_lib_path_changed( false ) +{ + m_ListLibr->InsertItems( *aCallersLibNames, 0 ); + + // Load user libs paths: + wxArrayString paths; + + SEARCH_STACK::Split( &paths, *aCallersProjectSpecificLibPaths ); + + for( unsigned i=0; iAppend( path ); + } + + // Display actual library paths which come in part from KIFACE::KifaceSearch() + // along with aCallersProjectSpecificLibPaths at the front. + SEARCH_STACK* libpaths = Prj().SchSearchS(); + + DBG( libpaths->Show( __func__ ); ) + + for( unsigned ii = 0; ii < libpaths->GetCount(); ii++ ) + { + m_DefaultLibraryPathslistBox->Append( (*libpaths)[ii] ); + } + + // select the first path after the current project's path + if( libpaths->GetCount() > 1 ) + m_DefaultLibraryPathslistBox->Select( 1 ); + + // Load setting for cache rescue + m_config = Kiface().KifaceSettings(); + bool rescueNeverShow = false; + m_config->Read( RESCUE_NEVER_SHOW_KEY, &rescueNeverShow, false ); + m_cbRescue->SetValue( !rescueNeverShow ); + + wxString msg = wxString::Format( _( + "Project '%s'" ), + GetChars( Prj().GetProjectFullName() ) + ); + + SetTitle( msg ); + + if( GetSizer() ) + GetSizer()->SetSizeHints( this ); + + m_sdbSizer1OK->SetDefault(); +} + + +void DIALOG_EESCHEMA_CONFIG::OnButtonUpClick( wxCommandEvent& event ) +{ + wxArrayInt selections; + + m_ListLibr->GetSelections( selections ); + + if ( selections.GetCount() <= 0 ) // No selection. + return; + + if( selections[0] == 0 ) // The first lib is selected. cannot move up it + return; + + wxArrayString libnames = m_ListLibr->GetStrings(); + + for( size_t ii = 0; ii < selections.GetCount(); ii++ ) + { + int jj = selections[ii]; + std::swap( libnames[jj], libnames[jj-1]); + } + + m_ListLibr->Set(libnames); + + // Reselect previously selected names + for( size_t ii = 0; ii < selections.GetCount(); ii++ ) + { + int jj = selections[ii]; + m_ListLibr->SetSelection(jj-1); + } + + m_lib_list_changed = true; +} + + +void DIALOG_EESCHEMA_CONFIG::OnButtonDownClick( wxCommandEvent& event ) +{ + wxArrayInt selections; + + m_ListLibr->GetSelections(selections); + + if ( selections.GetCount() <= 0 ) // No selection. + return; + + // The last lib is selected. cannot move down it + if( selections.Last() == (int)(m_ListLibr->GetCount()-1) ) + return; + + wxArrayString libnames = m_ListLibr->GetStrings(); + + for( int ii = selections.GetCount()-1; ii >= 0; ii-- ) + { + int jj = selections[ii]; + std::swap( libnames[jj], libnames[jj+1]); + } + + m_ListLibr->Set( libnames ); + + // Reselect previously selected names + for( size_t ii = 0; ii < selections.GetCount(); ii++ ) + { + int jj = selections[ii]; + m_ListLibr->SetSelection(jj+1); + } + + m_lib_list_changed = true; +} + + +void DIALOG_EESCHEMA_CONFIG::OnCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +void DIALOG_EESCHEMA_CONFIG::OnOkClick( wxCommandEvent& event ) +{ + // Give caller the changed paths + if( m_lib_path_changed ) + { + wxString paths; + + for( unsigned ii = 0; ii < m_listUserPaths->GetCount(); ii++ ) + { + if( ii > 0 ) + paths += wxT( ';' ); + + paths += m_listUserPaths->GetString( ii ); + } + + *m_callers_project_specific_lib_paths = paths; + } + + // Update caller's lib_names if changed. + if( m_lib_list_changed ) + { + wxArrayString list; + + for( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii ++ ) + list.Add( m_ListLibr->GetString( ii ) ); + + // Recreate lib list + *m_callers_lib_names = list; + } + + m_config->Write( RESCUE_NEVER_SHOW_KEY, ! m_cbRescue->GetValue() ); + + EndModal( wxID_OK ); +} + + +void DIALOG_EESCHEMA_CONFIG::OnCloseWindow( wxCloseEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +void DIALOG_EESCHEMA_CONFIG::OnRemoveLibClick( wxCommandEvent& event ) +{ + wxArrayInt selections; + + m_ListLibr->GetSelections( selections ); + + for( int ii = selections.GetCount()-1; ii >= 0; ii-- ) + { + m_ListLibr->Delete( selections[ii] ); + m_lib_list_changed = true; + } + + // Select next item after deleted in m_ListLibr + if( m_ListLibr->GetCount() > 0 && selections.GetCount() > 0 ) + { + int pos = selections[selections.GetCount()-1]; + + if( pos == (int)m_ListLibr->GetCount() ) + pos = m_ListLibr->GetCount() - 1; + + m_ListLibr->SetSelection( pos ); + } +} + + +void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) +{ + int ii; + wxString libfilename; + wxArrayInt selections; + + PROJECT& prj = Prj(); + + m_ListLibr->GetSelections( selections ); + + ii = selections.GetCount(); + + if( ii > 0 ) + ii = selections[0]; + else + ii = 0; + + wxString selection = m_DefaultLibraryPathslistBox->GetStringSelection(); + wxString libpath = Prj().AbsolutePath( selection ); + + if( !libpath ) + { + libpath = prj.GetRString( PROJECT::SCH_LIB_PATH ); + } + + wxFileDialog filesDialog( this, _( "Library files:" ), libpath, + wxEmptyString, SchematicLibraryFileWildcard, + wxFD_DEFAULT_STYLE | wxFD_MULTIPLE ); + + if( filesDialog.ShowModal() != wxID_OK ) + return; + + wxArrayString filenames; + + filesDialog.GetPaths( filenames ); + + wxFileName fn; + + // Build libs paths, to find later a relative path: + wxArrayString paths; + + for( unsigned ll=0; ll < m_DefaultLibraryPathslistBox->GetCount(); ++ll ) + paths.Add( m_DefaultLibraryPathslistBox->GetString( ll ) ); + + for( unsigned ll=0; ll < m_listUserPaths->GetCount(); ++ll ) + paths.Add( m_listUserPaths->GetString( ll ) ); + + for( unsigned jj = 0; jj < filenames.GetCount(); jj++ ) + { + fn = filenames[jj]; + + if( jj == 0 ) + prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() ); + + // Extension is not stored, so remove extension: + fn.SetExt( wxEmptyString ); + + // Try to use relative path: + for( unsigned ll = 0; ll < paths.GetCount(); ll++ ) + { + wxFileName relfn = fn; + relfn.MakeRelativeTo( paths[ll] ); + + if( relfn.GetPath()[0] != '.' ) + { + fn = relfn; + break; + } + } + + libfilename = fn.GetFullPath(); + + // Add or insert new library name, if not already in list + if( m_ListLibr->FindString( libfilename, fn.IsCaseSensitive() ) == wxNOT_FOUND ) + { + m_lib_list_changed = true; + + if( event.GetId() == ID_ADD_LIB ) + m_ListLibr->Append( libfilename ); + else + m_ListLibr->Insert( libfilename, ii++ ); + } + else + { + wxString msg = wxString::Format( _( + "'%s' : library already in use" ), + GetChars( libfilename ) + ); + DisplayError( this, msg ); + } + } +} + + +void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) +{ + PROJECT& prj = Prj(); + wxString abs_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); + wxString path; + + bool select = EDA_PATH_SELECTOR( _( "Default Path for Libraries" ), + abs_path, wxDD_DEFAULT_STYLE, + this, wxDefaultPosition ); + + if( !select ) + return; + + if( !wxFileName::DirExists( abs_path ) ) // Should not occur + return; + + // Add or insert path if not already in list + if( m_listUserPaths->FindString( abs_path ) == wxNOT_FOUND ) + { + int ipos = m_listUserPaths->GetCount(); + + if( event.GetId() == wxID_INSERT_PATH ) + { + if( ipos ) + ipos--; + + int jj = m_listUserPaths->GetSelection(); + + if( jj >= 0 ) + ipos = jj; + } + + // Ask the user if this is a relative path + int diag = wxMessageBox( _( "Use a relative path?" ), _( "Path type" ), + wxYES_NO | wxICON_QUESTION, this ); + + if( diag == wxYES ) + { + // Make it relative + wxFileName fn = abs_path; + fn.MakeRelativeTo( wxPathOnly( Prj().GetProjectFullName() ) ); + path = fn.GetPathWithSep() + fn.GetFullName(); + } + else + path = abs_path; + + m_listUserPaths->Insert( path, ipos ); + m_lib_path_changed = true; + + m_DefaultLibraryPathslistBox->InsertItems( 1, &path, ipos+1 ); + } + else + { + DisplayError( this, _("Path already in use") ); + } + + prj.SetRString( PROJECT::SCH_LIB_PATH, abs_path ); +} + + +static void remove_from_listbox( wxListBox* aListBox, const wxString& aText ) +{ + wxArrayString a; + + for( int i=0, cnt = aListBox->GetCount(); iGetString( i ); + + if( item != aText ) + a.Add( item ); + } + + aListBox->Clear(); + + aListBox->InsertItems( a, 0 ); +} + + +void DIALOG_EESCHEMA_CONFIG::OnRemoveUserPath( wxCommandEvent& event ) +{ + int ii = m_listUserPaths->GetSelection(); + + if( ii < 0 ) + ii = m_listUserPaths->GetCount()-1; + + if( ii >= 0 ) + { + wxString sel = m_listUserPaths->GetStringSelection(); + + remove_from_listbox( m_DefaultLibraryPathslistBox, sel ); + + m_listUserPaths->Delete( ii ); + m_lib_path_changed = true; + } +} + + +bool InvokeEeschemaConfig( wxWindow* aParent, + wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames ) +{ + DIALOG_EESCHEMA_CONFIG dlg( aParent, + aCallersProjectSpecificLibPaths, aCallersLibNames ); + + int ret = dlg.ShowModal(); + + return wxID_OK == ret; +} diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.cpp b/eeschema/dialogs/dialog_eeschema_config_fbp.cpp new file mode 100644 index 00000000..5ac72bcc --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.cpp @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_eeschema_config_fbp.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_EESCHEMA_CONFIG_FBP::DIALOG_EESCHEMA_CONFIG_FBP( 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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerUpper; + bSizerUpper = new wxBoxSizer( wxVERTICAL ); + + m_staticTextLibsList = new wxStaticText( this, wxID_ANY, _("Component library files"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextLibsList->Wrap( -1 ); + bSizerUpper->Add( m_staticTextLibsList, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerLibsChoice; + bSizerLibsChoice = new wxBoxSizer( wxHORIZONTAL ); + + m_ListLibr = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_EXTENDED|wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_SINGLE ); + m_ListLibr->SetToolTip( _("List of active library files.\nOnly library files in this list are loaded by Eeschema.\nThe order of this list is important:\nEeschema searchs for a given component using this list order priority.") ); + m_ListLibr->SetMinSize( wxSize( 400,250 ) ); + + bSizerLibsChoice->Add( m_ListLibr, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bRightSizer; + bRightSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonAddLib = new wxButton( this, ID_ADD_LIB, _("Add"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonAddLib->SetToolTip( _("Add a new library after the selected library, and load it") ); + + bRightSizer->Add( m_buttonAddLib, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 ); + + m_buttonIns = new wxButton( this, wxID_ANY, _("Insert"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonIns->SetToolTip( _("Add a new library before the selected library, and load it") ); + + bRightSizer->Add( m_buttonIns, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 ); + + m_buttonRemoveLib = new wxButton( this, ID_REMOVE_LIB, _("Remove"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonRemoveLib->SetToolTip( _("Unload the selected library") ); + + bRightSizer->Add( m_buttonRemoveLib, 0, wxALL|wxEXPAND, 5 ); + + m_buttonUp = new wxButton( this, wxID_ANY, _("Up"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonUp, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_buttonDown = new wxButton( this, wxID_ANY, _("Down"), wxDefaultPosition, wxDefaultSize, 0 ); + bRightSizer->Add( m_buttonDown, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + + bSizerLibsChoice->Add( bRightSizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bSizerUpper->Add( bSizerLibsChoice, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bSizerUpper, 2, wxEXPAND, 5 ); + + wxBoxSizer* bSizerMiddle; + bSizerMiddle = new wxBoxSizer( wxVERTICAL ); + + m_staticTextPaths = new wxStaticText( this, wxID_ANY, _("User defined search path"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPaths->Wrap( -1 ); + bSizerMiddle->Add( m_staticTextPaths, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerPathsChoice; + bSizerPathsChoice = new wxBoxSizer( wxHORIZONTAL ); + + m_listUserPaths = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_SINGLE ); + m_listUserPaths->SetToolTip( _("Additional paths used in this project. The priority is higher than default KiCad paths.") ); + m_listUserPaths->SetMinSize( wxSize( 400,90 ) ); + + bSizerPathsChoice->Add( m_listUserPaths, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bUserPathsButtonsSizer; + bUserPathsButtonsSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonAddPath = new wxButton( this, ID_LIB_PATH_SEL, _("Add"), wxDefaultPosition, wxDefaultSize, 0 ); + bUserPathsButtonsSizer->Add( m_buttonAddPath, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 ); + + m_buttonInsPath = new wxButton( this, wxID_INSERT_PATH, _("Insert"), wxDefaultPosition, wxDefaultSize, 0 ); + bUserPathsButtonsSizer->Add( m_buttonInsPath, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 ); + + m_buttonRemovePath = new wxButton( this, wxID_REMOVE_PATH, _("Remove"), wxDefaultPosition, wxDefaultSize, 0 ); + bUserPathsButtonsSizer->Add( m_buttonRemovePath, 0, wxALL|wxEXPAND, 5 ); + + + bSizerPathsChoice->Add( bUserPathsButtonsSizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bSizerMiddle->Add( bSizerPathsChoice, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bSizerMiddle, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizerLower; + bSizerLower = new wxBoxSizer( wxVERTICAL ); + + m_staticTextPathlist = new wxStaticText( this, wxID_ANY, _("Current search path list"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPathlist->Wrap( -1 ); + bSizerLower->Add( m_staticTextPathlist, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_DefaultLibraryPathslistBox = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_NEEDED_SB ); + m_DefaultLibraryPathslistBox->SetToolTip( _("System and user paths used to search and load library files and component doc files.\nSorted by decreasing priority order.") ); + + bSizerLower->Add( m_DefaultLibraryPathslistBox, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bMainSizer->Add( bSizerLower, 1, wxEXPAND, 5 ); + + m_cbRescue = new wxCheckBox( this, wxID_ANY, _("Check for cache/library conflicts when loading schematic"), wxDefaultPosition, wxDefaultSize, 0 ); + bMainSizer->Add( m_cbRescue, 0, wxALL, 5 ); + + m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bMainSizer->Add( m_staticline3, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + bMainSizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnCloseWindow ) ); + m_ListLibr->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnFilesListClick ), NULL, this ); + m_ListLibr->Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnFilesListClick ), NULL, this ); + m_buttonAddLib->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertLibClick ), NULL, this ); + m_buttonIns->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertLibClick ), NULL, this ); + m_buttonRemoveLib->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnRemoveLibClick ), NULL, this ); + m_buttonUp->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnButtonUpClick ), NULL, this ); + m_buttonDown->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnButtonDownClick ), NULL, this ); + m_buttonAddPath->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertPath ), NULL, this ); + m_buttonInsPath->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertPath ), NULL, this ); + m_buttonRemovePath->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnRemoveUserPath ), NULL, this ); + m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnCancelClick ), NULL, this ); + m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnOkClick ), NULL, this ); +} + +DIALOG_EESCHEMA_CONFIG_FBP::~DIALOG_EESCHEMA_CONFIG_FBP() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnCloseWindow ) ); + m_ListLibr->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnFilesListClick ), NULL, this ); + m_ListLibr->Disconnect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnFilesListClick ), NULL, this ); + m_buttonAddLib->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertLibClick ), NULL, this ); + m_buttonIns->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertLibClick ), NULL, this ); + m_buttonRemoveLib->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnRemoveLibClick ), NULL, this ); + m_buttonUp->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnButtonUpClick ), NULL, this ); + m_buttonDown->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnButtonDownClick ), NULL, this ); + m_buttonAddPath->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertPath ), NULL, this ); + m_buttonInsPath->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnAddOrInsertPath ), NULL, this ); + m_buttonRemovePath->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnRemoveUserPath ), NULL, this ); + m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnCancelClick ), NULL, this ); + m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EESCHEMA_CONFIG_FBP::OnOkClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.fbp b/eeschema/dialogs/dialog_eeschema_config_fbp.fbp new file mode 100644 index 00000000..72fcc430 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.fbp @@ -0,0 +1,1588 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_eeschema_config_fbp + 1000 + none + 1 + dialog_eeschema_config + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_EESCHEMA_CONFIG_FBP + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + + + + + + + + + + + + + + + OnCloseWindow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 2 + + + bSizerUpper + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Component library files + + 0 + + + 0 + + 1 + m_staticTextLibsList + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerLibsChoice + wxHORIZONTAL + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 400,250 + 1 + m_ListLibr + 1 + + + protected + 1 + + Resizable + 1 + + wxLB_EXTENDED|wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_SINGLE + + 0 + List of active library files. Only library files in this list are loaded by Eeschema. The order of this list is important: Eeschema searchs for a given component using this list order priority. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + OnFilesListClick + OnFilesListClick + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + + bRightSizer + wxVERTICAL + none + + 5 + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ADD_LIB + Add + + 0 + + + 0 + + 1 + m_buttonAddLib + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a new library after the selected library, and load it + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddOrInsertLibClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Insert + + 0 + + + 0 + + 1 + m_buttonIns + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a new library before the selected library, and load it + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddOrInsertLibClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_REMOVE_LIB + Remove + + 0 + + + 0 + + 1 + m_buttonRemoveLib + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Unload the selected library + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRemoveLibClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Up + + 0 + + + 0 + + 1 + m_buttonUp + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonUpClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Down + + 0 + + + 0 + + 1 + m_buttonDown + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonDownClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerMiddle + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + User defined search path + + 0 + + + 0 + + 1 + m_staticTextPaths + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerPathsChoice + wxHORIZONTAL + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 400,90 + 1 + m_listUserPaths + 1 + + + protected + 1 + + Resizable + 1 + + wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_SINGLE + + 0 + Additional paths used in this project. The priority is higher than default KiCad paths. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + + bUserPathsButtonsSizer + wxVERTICAL + none + + 5 + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_LIB_PATH_SEL + Add + + 0 + + + 0 + + 1 + m_buttonAddPath + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddOrInsertPath + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_INSERT_PATH + Insert + + 0 + + + 0 + + 1 + m_buttonInsPath + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddOrInsertPath + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_REMOVE_PATH + Remove + + 0 + + + 0 + + 1 + m_buttonRemovePath + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRemoveUserPath + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerLower + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Current search path list + + 0 + + + 0 + + 1 + m_staticTextPathlist + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + -1,-1 + 1 + m_DefaultLibraryPathslistBox + 1 + + + protected + 1 + + Resizable + 1 + + wxLB_NEEDED_SB + + 0 + System and user paths used to search and load library files and component doc files. Sorted by decreasing priority order. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Check for cache/library conflicts when loading schematic + + 0 + + + 0 + + 1 + m_cbRescue + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline3 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + public + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.h b/eeschema/dialogs/dialog_eeschema_config_fbp.h new file mode 100644 index 00000000..5af47cd1 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.h @@ -0,0 +1,89 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EESCHEMA_CONFIG_FBP_H__ +#define __DIALOG_EESCHEMA_CONFIG_FBP_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_EESCHEMA_CONFIG_FBP +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_EESCHEMA_CONFIG_FBP : public DIALOG_SHIM +{ + private: + + protected: + enum + { + ID_ADD_LIB = 1000, + ID_REMOVE_LIB, + ID_LIB_PATH_SEL, + wxID_INSERT_PATH, + wxID_REMOVE_PATH + }; + + wxStaticText* m_staticTextLibsList; + wxListBox* m_ListLibr; + wxButton* m_buttonAddLib; + wxButton* m_buttonIns; + wxButton* m_buttonRemoveLib; + wxButton* m_buttonUp; + wxButton* m_buttonDown; + wxStaticText* m_staticTextPaths; + wxListBox* m_listUserPaths; + wxButton* m_buttonAddPath; + wxButton* m_buttonInsPath; + wxButton* m_buttonRemovePath; + wxStaticText* m_staticTextPathlist; + wxListBox* m_DefaultLibraryPathslistBox; + wxCheckBox* m_cbRescue; + wxStaticLine* m_staticline3; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseWindow( wxCloseEvent& event ) { event.Skip(); } + virtual void OnFilesListClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddOrInsertLibClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveLibClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonUpClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonDownClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddOrInsertPath( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveUserPath( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + DIALOG_EESCHEMA_CONFIG_FBP( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_EESCHEMA_CONFIG_FBP(); + +}; + +#endif //__DIALOG_EESCHEMA_CONFIG_FBP_H__ diff --git a/eeschema/dialogs/dialog_eeschema_options.cpp b/eeschema/dialogs/dialog_eeschema_options.cpp new file mode 100644 index 00000000..70541b71 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_options.cpp @@ -0,0 +1,371 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file dialog_eeschema_options.cpp + */ + +#include +#include + +#include + +#include "wx/settings.h" + +DIALOG_EESCHEMA_OPTIONS::DIALOG_EESCHEMA_OPTIONS( wxWindow* parent ) : + DIALOG_EESCHEMA_OPTIONS_BASE( parent ) +{ + m_choiceUnits->SetFocus(); + m_sdbSizerOK->SetDefault(); + + wxListItem col0; + col0.SetId( 0 ); + col0.SetText( _( "Field Name" ) ); + + wxListItem col1; + col1.SetId( 1 ); + col1.SetText( _( "Default Value" ) ); + + wxListItem col2; + col2.SetId( 2 ); + col2.SetText( _( "Visible" ) ); + + templateFieldListCtrl->InsertColumn( 0, col0 ); + templateFieldListCtrl->InsertColumn( 1, col1 ); + templateFieldListCtrl->InsertColumn( 2, col2 ); + + templateFieldListCtrl->SetColumnWidth( 0, templateFieldListCtrl->GetSize().GetWidth() / 3.5 ); + templateFieldListCtrl->SetColumnWidth( 1, templateFieldListCtrl->GetSize().GetWidth() / 3.5 ); + templateFieldListCtrl->SetColumnWidth( 2, templateFieldListCtrl->GetSize().GetWidth() / 3.5 ); + + // Invalid field selected + selectedField = -1; + + // Make sure we select the first tab of the options tab page + m_notebook->SetSelection( 0 ); + + // Connect the edit controls for the template field names to the kill focus event which + // doesn't propogate, hence the need to connect it here. + + fieldNameTextCtrl->Connect( wxEVT_KILL_FOCUS, + wxFocusEventHandler( DIALOG_EESCHEMA_OPTIONS::OnEditControlKillFocus ), NULL, this ); + + fieldDefaultValueTextCtrl->Connect( wxEVT_KILL_FOCUS, + wxFocusEventHandler( DIALOG_EESCHEMA_OPTIONS::OnEditControlKillFocus ), NULL, this ); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_EESCHEMA_OPTIONS::SetUnits( const wxArrayString& units, int select ) +{ + wxASSERT( units.GetCount() > 0 + && ( select >= 0 && (size_t) select < units.GetCount() ) ); + + m_choiceUnits->Append( units ); + m_choiceUnits->SetSelection( select ); +} + + +void DIALOG_EESCHEMA_OPTIONS::SetRefIdSeparator( wxChar aSep, wxChar aFirstId) +{ + // m_choiceSeparatorRefId displays one of + // "A" ".A" "-A" "_A" ".1" "-1" "_1" option + + int sel = 0; + switch( aSep ) + { + default: + case 0: + aFirstId = 'A'; // cannot use a number without separator + break; + + case '.': + sel = 1; + break; + + case '-': + sel = 2; + break; + + case '_': + sel = 3; + break; + } + + if( aFirstId == '1' ) + sel = 4; + + m_choiceSeparatorRefId->SetSelection( sel ); +} + +void DIALOG_EESCHEMA_OPTIONS::GetRefIdSeparator( int& aSep, int& aFirstId) +{ + // m_choiceSeparatorRefId displays one of + // "A" ".A" "-A" "_A" ".1" "-1" "_1" option + + aFirstId = 'A'; + switch( m_choiceSeparatorRefId->GetSelection() ) + { + default: + case 0: aSep = 0; break; + case 1: aSep = '.'; break; + case 2: aSep = '-'; break; + case 3: aSep = '_'; break; + case 4: aFirstId = '1'; aSep = '.'; break; + case 5: aFirstId = '1'; aSep = '-'; break; + case 6: aFirstId = '1'; aSep = '_'; break; + } +} + + +void DIALOG_EESCHEMA_OPTIONS::SetGridSizes( const GRIDS& aGridSizes, int aGridId ) +{ + wxASSERT( aGridSizes.size() > 0 ); + + int select = wxNOT_FOUND; + + for( size_t i = 0; i < aGridSizes.size(); i++ ) + { + wxString tmp; + tmp.Printf( wxT( "%0.1f" ), aGridSizes[i].m_Size.x ); + m_choiceGridSize->Append( tmp ); + + if( aGridSizes[i].m_CmdId == aGridId ) + select = (int) i; + } + + m_choiceGridSize->SetSelection( select ); +} + + +void DIALOG_EESCHEMA_OPTIONS::RefreshTemplateFieldView( void ) +{ + // Loop through the template fieldnames and add them to the list control + // or just change texts if room exists + long itemindex = 0; + wxString tmp; + + for( TEMPLATE_FIELDNAMES::iterator fld = templateFields.begin(); + fld != templateFields.end(); ++fld, itemindex++ ) + { + if( templateFieldListCtrl->GetItemCount() <= itemindex ) + { + templateFieldListCtrl->InsertItem( + templateFieldListCtrl->GetItemCount(), fld->m_Name ); + } + + wxListItem litem; + litem.SetId( itemindex ); + templateFieldListCtrl->GetItem( litem ); + + litem.SetColumn( 0 ); + if( litem.GetText() != fld->m_Name ) + templateFieldListCtrl->SetItem( itemindex, 0, fld->m_Name ); + + litem.SetColumn( 1 ); + if( litem.GetText() != fld->m_Value ) + templateFieldListCtrl->SetItem( itemindex, 1, fld->m_Value ); + + tmp = ( fld->m_Visible == true ) ? _( "Visible" ) : _( "Hidden" ); + + litem.SetColumn( 2 ); + if( litem.GetText() != tmp ) + templateFieldListCtrl->SetItem( itemindex, 2, tmp ); + } + + // Remove extra items: + while( templateFieldListCtrl->GetItemCount() > itemindex ) + { + templateFieldListCtrl->DeleteItem( itemindex ); + } + +} + + +void DIALOG_EESCHEMA_OPTIONS::SelectTemplateField( int aItem ) +{ + // Only select valid items! + if( ( aItem < 0 ) || ( aItem >= templateFieldListCtrl->GetItemCount() ) ) + return; + + // Make sure we select the new item in list control + if( templateFieldListCtrl->GetFirstSelected() != aItem ) + templateFieldListCtrl->Select( aItem, true ); +} + + +void DIALOG_EESCHEMA_OPTIONS::OnAddButtonClick( wxCommandEvent& event ) +{ + // If there is currently a valid selection, copy the edit panel to the + // selected field so as not to lose the data + if( fieldSelectionValid( selectedField ) ) + copyPanelToSelected(); + + // Add a new fieldname to the fieldname list + TEMPLATE_FIELDNAME newFieldname = TEMPLATE_FIELDNAME( "Fieldname" ); + newFieldname.m_Value = wxT( "Value" ); + newFieldname.m_Visible = false; + templateFields.push_back( newFieldname ); + + // Select the newly added field and then copy that data to the edit panel. + // Make sure any previously selected state is cleared and then select the + // new field + selectedField = templateFields.size() - 1; + + // Update the display to reflect the new data + RefreshTemplateFieldView(); + copySelectedToPanel(); + + // Make sure we select the new item + SelectTemplateField( selectedField ); + + event.Skip(); +} + + +void DIALOG_EESCHEMA_OPTIONS::OnDeleteButtonClick( wxCommandEvent& event ) +{ + // If there is currently a valid selection, delete the template field from + // the template field list + if( fieldSelectionValid( selectedField ) ) + { + // Delete the fieldname from the fieldname list + templateFields.erase( templateFields.begin() + selectedField ); + + // If the selectedField is still not in the templateField range now, + // make sure we stay in range and when there are no fields present + // move to -1 + if( selectedField >= int( templateFields.size() ) ) + selectedField = templateFields.size() - 1; + + // Update the display to reflect the new data + RefreshTemplateFieldView(); + + copySelectedToPanel(); + + // Make sure after the refresh that the selected item is correct + SelectTemplateField( selectedField ); + } +} + + +void DIALOG_EESCHEMA_OPTIONS::copyPanelToSelected( void ) +{ + if( !fieldSelectionValid( selectedField ) ) + return; + + // Update the template field from the edit panel + templateFields[selectedField].m_Name = fieldNameTextCtrl->GetValue(); + templateFields[selectedField].m_Value = fieldDefaultValueTextCtrl->GetValue(); + templateFields[selectedField].m_Visible = fieldVisibleCheckbox->GetValue(); +} + + +void DIALOG_EESCHEMA_OPTIONS::OnEditControlKillFocus( wxFocusEvent& event ) +{ + // Update the data + UI + copyPanelToSelected(); + RefreshTemplateFieldView(); + SelectTemplateField( selectedField ); + + event.Skip(); +} + +void DIALOG_EESCHEMA_OPTIONS::OnEnterKey( wxCommandEvent& event ) +{ + // Process the event produced when the user presses enter key + // in template fieldname text control or template fieldvalue text control + // Validate the current name or value, and switch focus to the other param + // (value or name) + copyPanelToSelected(); + RefreshTemplateFieldView(); + + if( fieldNameTextCtrl->HasFocus() ) + fieldDefaultValueTextCtrl->SetFocus(); + else + fieldNameTextCtrl->SetFocus(); +} + + +void DIALOG_EESCHEMA_OPTIONS::OnVisibleFieldClick( wxCommandEvent& event ) +{ + // Process the event produced when the user click on + // the check box which controls the field visibility + copyPanelToSelected(); + RefreshTemplateFieldView(); +} + +void DIALOG_EESCHEMA_OPTIONS::copySelectedToPanel( void ) +{ + if( !fieldSelectionValid( selectedField ) ) + return; + + // Update the panel data from the selected template field + fieldNameTextCtrl->SetValue( templateFields[selectedField].m_Name ); + fieldDefaultValueTextCtrl->SetValue( templateFields[selectedField].m_Value ); + fieldVisibleCheckbox->SetValue( templateFields[selectedField].m_Visible ); +} + + +void DIALOG_EESCHEMA_OPTIONS::OnTemplateFieldSelected( wxListEvent& event ) +{ + // Before getting the new field data, make sure we save the old! + copyPanelToSelected(); + + // Now update the selected field and copy the data from the field to the + // edit panel + selectedField = event.GetIndex(); + copySelectedToPanel(); +} + + +void DIALOG_EESCHEMA_OPTIONS::SetTemplateFields( const TEMPLATE_FIELDNAMES& aFields ) +{ + // Set the template fields object + templateFields = aFields; + + // select the last field ( will set selectedField to -1 if no field ): + selectedField = templateFields.size()-1; + + // Build and refresh the view + RefreshTemplateFieldView(); + + if( selectedField >= 0 ) + { + copySelectedToPanel(); + SelectTemplateField( selectedField ); + } + +} + + +TEMPLATE_FIELDNAMES DIALOG_EESCHEMA_OPTIONS::GetTemplateFields( void ) +{ + return templateFields; +} + diff --git a/eeschema/dialogs/dialog_eeschema_options.h b/eeschema/dialogs/dialog_eeschema_options.h new file mode 100644 index 00000000..12446b9f --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_options.h @@ -0,0 +1,479 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file dialog_eeschema_options.h + * + * Subclass of DIALOG_EESCHEMA_OPTIONS_BASE, which is generated by wxFormBuilder. + */ + +#ifndef __dialog_eeschema_options__ +#define __dialog_eeschema_options__ + +#include +#include + +class DIALOG_EESCHEMA_OPTIONS : public DIALOG_EESCHEMA_OPTIONS_BASE +{ +protected: + /** @brief The template fieldnames for this dialog */ + TEMPLATE_FIELDNAMES templateFields; + + /** @brief The current row selected in the template fieldname wxListCtrl which is also in the + * edit panel + * selectedField = -1 when no valid item selected + */ + int selectedField; + + /** @brief return true if aFieldId is a valid field selection + */ + bool fieldSelectionValid( int aFieldId ) + { + return ( aFieldId >= 0 ) && ( aFieldId < int( templateFields.size() ) ); + } + + /** + * Function OnEnterKey (virtual) + * Process the wxWidgets @a event produced when the user presses enter key + * in template fieldname text control or template fieldvalue text control + */ + void OnEnterKey( wxCommandEvent& event ); + + /** + * Function OnVisibleFieldClick (virtual) + * Process the wxWidgets @a event produced when the user click on + * the check box which controls the field visibility + */ + void OnVisibleFieldClick( wxCommandEvent& event ); + + /** + * Function OnAddButtonClick + * Process the wxWidgets @a event produced when the user presses the Add buton for the + * template fieldnames control + * + * @param event The wxWidgets produced event information + * + * Adds a new template fieldname (with default values) to the template fieldnames data + */ + void OnAddButtonClick( wxCommandEvent& event ); + + /** + * Function OnDeleteButtonClick + * Process the wxWidgets @a event produced when the user presses the Delete button for the + * template fieldnames control + * + * @param event The wxWidgets produced event information + * + * Deletes the selected template fieldname from the template fieldnames data + */ + void OnDeleteButtonClick( wxCommandEvent& event ); + + /** + * Function OnEditControlKillFocus + * This Focus Event Handler should be connected to any controls in the template field edit box + * so that any loss of focus results in the data being saved to the currently selected template + * field + * + * @param event The wxWidgets produced event information + * + * Copies data from the edit box to the selected field template + */ + void OnEditControlKillFocus( wxFocusEvent& event ); + + /** + * Function copyPanelToSelected + * Copies the data from the edit panel to the selected template fieldname + */ + void copyPanelToSelected( void ); + + /** + * Function copySelectedToPanel + * Copies the data from the selected template fieldname and fills in the edit panel + */ + void copySelectedToPanel( void ); + + /** + * Function OnTemplateFieldSelected + * Event handler for the wxListCtrl containing the template fieldnames + * + * @param event The event information provided by wxWidgets + * + * Processes data exchange between the edit panel and the selected template fieldname + */ + void OnTemplateFieldSelected( wxListEvent& event ); + + /** + * Function RefreshTemplateFieldView + * Refresh the template fieldname wxListCtrl + * + * Deletes all data from the wxListCtrl and then re-polpulates the control with the data in + * the template fieldnames. + * + * Use any time the template field data has changed + */ + void RefreshTemplateFieldView( void ); + + /** + * Function SelectTemplateField + * Selects @a aItem from the wxListCtrl populated with the template fieldnames + * + * @param aItem The item index of the row to be selected + * + * When RefreshTemplateFieldView() is used the selection is lost because all of the items are + * removed from the wxListCtrl and then the control is re-populated. This function can be used + * to re-select an item that was previously selected so that the selection is not lost. + * + * NOTE: This function first sets the ignoreSelection flag before making the selection. + * This means the class can select something in the wxListCtrl without causing further + * selection events. + */ + void SelectTemplateField( int aItem ); + +public: + /** + * Public constructor + * + * @param parent The dialog's parent + */ + DIALOG_EESCHEMA_OPTIONS( wxWindow* parent ); + + /** + * Function GetUnitsSelection + * Returns the currently selected grid size in the dialog + */ + int GetUnitsSelection( void ) { return m_choiceUnits->GetSelection(); } + + /** + * Function SetUnits + * Set the unit options + * + * @param units The array of strings representing the unit options + * @param select The unit to select from the unit options + * + * Appends the @a units options to the list of unit options and selects the @a aSelect option + */ + void SetUnits( const wxArrayString& units, int aSelect = 0 ); + + /** + * Function GetGridSelection + * Returns the curent grid size selected in the dialog + */ + int GetGridSelection( void ) { return m_choiceGridSize->GetSelection(); } + + /** + * Function SetGridSizes + * Sets the available grid size choices @a aGridSizes and selectd the current option @a aGridId + * + * @param aGridSizes The grid sizes that are able to be chosen from + * @param aGridId The grid size to select from the grid size options + */ + void SetGridSizes( const GRIDS& aGridSizes, int aGridId ); + + /** + * Function GetBusWidth + * Get the current bus width setting from the dialog + */ + int GetBusWidth( void ) { return m_spinBusWidth->GetValue(); } + + /** + * Function SetBusWidth + * Sets the bus width setting in the dialog + * + * @param aWidth The bus width to set the dialog edit spinbox with + */ + void SetBusWidth( int aWidth ) { m_spinBusWidth->SetValue( aWidth ); } + + /** + * Function SetLineWidth + * Sets the current LineWidth value in the dialog + * @param aWidth The line width to set in the dialog + */ + void SetLineWidth( int aWidth ) { m_spinLineWidth->SetValue( aWidth ); } + + /** + * Function GetLineWidth + * Returns the current LineWidth value from the dialog + */ + int GetLineWidth( void ) { return m_spinLineWidth->GetValue(); } + + /** + * Function SetTextSize + * Sets the current default TextSize value in the dialog + * @param text_size The text size to set in the dialog + */ + void SetTextSize( int text_size ) { m_spinTextSize->SetValue( text_size ); } + + /** + * Function GetTextSize + * Returns the current default TextSize value from the dialog + */ + int GetTextSize( void ) { return m_spinTextSize->GetValue(); } + + /** + * Function SetRepeatHorizontal + * Sets the current RepeatHorizontal displacement value in the dialog + * @param displacement The displacement to set in the dialog + */ + void SetRepeatHorizontal( int displacement ) + { + m_spinRepeatHorizontal->SetValue( displacement ); + } + + /** + * Function GetRepeatHorizontal + * Returns the current RepeatHorizontal displacement value from the dialog + */ + int GetRepeatHorizontal( void ) { return m_spinRepeatHorizontal->GetValue(); } + + /** + * Function SetRepeatVertical + * Sets the current RepeatVertical displacement value in the dialog + * @param displacement The displacement to set in the dialog + */ + void SetRepeatVertical( int displacement ) { m_spinRepeatVertical->SetValue( displacement ); } + + /** + * Function GetRepeatVertical + * Returns the current RepeatVertical displacement value from the dialog + */ + int GetRepeatVertical( void ) { return m_spinRepeatVertical->GetValue(); } + + /** + * Function SetRepeatLabel + * Sets the current RepeatLabel increment value in the dialog + * @param increment The increment to set in the dialog + */ + void SetRepeatLabel( int increment ) { m_spinRepeatLabel->SetValue( increment ); } + + /** + * Function GetRepeatLabel + * Returns the current RepeatLabel increment value from the dialog + */ + int GetRepeatLabel( void ) { return m_spinRepeatLabel->GetValue(); } + + /** + * Function SetAutoSaveInterval + * Sets the current AutoSaveInterval value in the dialog + * @param aInterval The interval to set in the dialog + */ + void SetAutoSaveInterval( int aInterval ) { m_spinAutoSaveInterval->SetValue( aInterval ); } + + /** + * Function GetAutoSaveInterval + * Returns the current AutoSaveInterval value from the dialog + */ + int GetAutoSaveInterval() const { return m_spinAutoSaveInterval->GetValue(); } + + /** + * Function SetMaxUndoItems + * Sets the maximum number of undo items + * @param aItems the number to set + */ + void SetMaxUndoItems( int aItems ) { m_spinMaxUndoItems->SetValue( aItems ); } + + /** + * Function GetMaxUndoItems + * Return the current maximum number of undo items + */ + int GetMaxUndoItems() const { return m_spinMaxUndoItems->GetValue(); } + + /** + * Function SetRefIdSeparator + * Sets the current RefIdSeparator value in the dialog + * @param aSep The seperator to use between the reference and the part ID + * @param aFirstId The first part ID, currently either 'A' or '1' + */ + void SetRefIdSeparator( wxChar aSep, wxChar aFirstId); + + /** + * Function GetRefIdSeparator + * Returns the current RefIdSeparator value from the dialog + * @param aSep The OUTPUT seperator value + * @param aFirstId The OUTPUT reference first ID + */ + void GetRefIdSeparator( int& aSep, int& aFirstId); + + /** + * Function SetShowGrid + * Sets the current ShowGrid value in the dialog + * @param show The ShowGrid value to set in the dialog + */ + void SetShowGrid( bool show ) { m_checkShowGrid->SetValue( show ); } + + /** + * Function GetShowGrid + * Returns the current ShowGrid value from the dialog + */ + bool GetShowGrid( void ) { return m_checkShowGrid->GetValue(); } + + /** + * Function SetShowHiddenPins + * Sets the current ShowHiddenPins value in the dialog + * @param show The ShowHiddenPins value to set in the dialog + */ + void SetShowHiddenPins( bool show ) { m_checkShowHiddenPins->SetValue( show ); } + + /** + * Function GetShowHiddenPins + * Returns the current ShowHiddenPins value from the dialog + */ + bool GetShowHiddenPins( void ) { return m_checkShowHiddenPins->GetValue(); } + + /** + * Function SetEnableZoomNoCenter + * Sets the current ZoomNoCenter value in the dialog + * @param enable The ZoomNoCenter value to set in the dialog + */ + void SetEnableZoomNoCenter( bool enable ) + { + m_checkEnableZoomCenter->SetValue( !enable ); + } + + /** + * Function GetEnableZoomNoCenter + * Returns the current ZoomNoCenter value from the dialog + */ + bool GetEnableZoomNoCenter( void ) + { + return !m_checkEnableZoomCenter->GetValue(); + } + + /** + * Function SetEnableMiddleButtonPan + * Sets the current MiddleButtonPan value in the dialog + * + * @param enable The boolean value to set the MiddleButtonPan value in the dialog + */ + void SetEnableMiddleButtonPan( bool enable ) + { + m_checkEnableMiddleButtonPan->SetValue( enable ); + m_checkMiddleButtonPanLimited->Enable( enable ); + } + + /** + * Function GetEnableMiddleButtonPan + * Returns the current MiddleButtonPan setting from the dialog + */ + bool GetEnableMiddleButtonPan( void ) + { + return m_checkEnableMiddleButtonPan->GetValue(); + } + + /** + * Function SetMiddleButtonPanLimited + * Sets the MiddleButtonPanLimited value in the dialog + * + * @param enable The boolean value to set the MiddleButtonPanLimted value in the dialog + */ + void SetMiddleButtonPanLimited( bool enable ) + { + m_checkMiddleButtonPanLimited->SetValue( enable ); + } + + /** + * Function GetMiddleButtonPanLimited + * Returns the MiddleButtonPanLimited setting from the dialog + */ + bool GetMiddleButtonPanLimited( void ) + { + return m_checkMiddleButtonPanLimited->GetValue(); + } + + /** + * Function SetEnableMousewheelPan + * Sets the MousewheelPan setting in the dialog + * + * @param enable The boolean value to set the AutoPan value in the dialog + */ + void SetEnableMousewheelPan( bool enable ) { m_checkEnableMousewheelPan->SetValue( enable ); } + + /** + * Function GetEnableMousewheelPan + * Return the MousewheelPan setting from the dialog + */ + bool GetEnableMousewheelPan( void ) { return m_checkEnableMousewheelPan->GetValue(); } + + /** + * Function SetEnableAutoPan + * Sets the AutoPan setting in the dialog + * + * @param enable The boolean value to set the AutoPan value in the dialog + */ + void SetEnableAutoPan( bool enable ) { m_checkAutoPan->SetValue( enable ); } + + /** + * Function GetEnableAutoPan + * Return the AutoPan setting from the dialog + */ + bool GetEnableAutoPan( void ) { return m_checkAutoPan->GetValue(); } + + /** + * Function SetEnableHVBusOrientation + * Set the HVBusOrientation setting in the dialog + * + * @param enable The boolean value to set the HVBusOrientation value in the dialog + */ + void SetEnableHVBusOrientation( bool enable ) { m_checkHVOrientation->SetValue( enable ); } + + /** + * Function GetEnableHVBusOrientation + * Get the HVBusOrientation setting from the dialog + */ + bool GetEnableHVBusOrientation( void ) { return m_checkHVOrientation->GetValue(); } + + /** + * Function + * Set the ShowPageLimits setting in the dialog + */ + void SetShowPageLimits( bool show ) { m_checkPageLimits->SetValue( show ); } + + /** + * Function + * Return the current ShowPageLimits setting from the dialog + */ + bool GetShowPageLimits( void ) { return m_checkPageLimits->GetValue(); } + + /** + * Function SetTemplateFields + * Set the template field data in the dialog + * + * @param aFields The template fieldnames that the dialog should start with before any editing + */ + void SetTemplateFields( const TEMPLATE_FIELDNAMES& aFields ); + + /** + * Function GetTemplateFields + * Get the dialog's template field data + * + */ + TEMPLATE_FIELDNAMES GetTemplateFields( void ); + +private: + void OnMiddleBtnPanEnbl( wxCommandEvent& event ) + { + m_checkMiddleButtonPanLimited->Enable( GetEnableMiddleButtonPan() ); + } +}; + +#endif // __dialog_eeschema_options__ diff --git a/eeschema/dialogs/dialog_eeschema_options_base.cpp b/eeschema/dialogs/dialog_eeschema_options_base.cpp new file mode 100644 index 00000000..ee48fbdc --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_options_base.cpp @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_eeschema_options_base.h" + +/////////////////////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE( DIALOG_EESCHEMA_OPTIONS_BASE, DIALOG_SHIM ) + EVT_SIZE( DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnSize ) + EVT_CHOICE( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnChooseUnits ) + EVT_CHECKBOX( xwID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnMiddleBtnPanEnbl ) + EVT_LIST_ITEM_DESELECTED( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnTemplateFieldDeselected ) + EVT_LIST_ITEM_SELECTED( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnTemplateFieldSelected ) + EVT_TEXT_ENTER( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnEnterKey ) + EVT_TEXT_ENTER( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnEnterKey ) + EVT_CHECKBOX( wxID_ANY, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnVisibleFieldClick ) + EVT_BUTTON( wxID_ADD_FIELD, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnAddButtonClick ) + EVT_BUTTON( wxID_DELETE_FIELD, DIALOG_EESCHEMA_OPTIONS_BASE::_wxFB_OnDeleteButtonClick ) +END_EVENT_TABLE() + +DIALOG_EESCHEMA_OPTIONS_BASE::DIALOG_EESCHEMA_OPTIONS_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bOptionsSizer; + bOptionsSizer = new wxBoxSizer( wxVERTICAL ); + + m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_notebook->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + + m_panel1 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* p1mainSizer; + p1mainSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer1->AddGrowableCol( 0 ); + fgSizer1->AddGrowableCol( 1 ); + fgSizer1->AddGrowableCol( 2 ); + fgSizer1->SetFlexibleDirection( wxBOTH ); + fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText2 = new wxStaticText( m_panel1, wxID_ANY, _("&Measurement units:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + fgSizer1->Add( m_staticText2, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + wxArrayString m_choiceUnitsChoices; + m_choiceUnits = new wxChoice( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceUnitsChoices, 0 ); + m_choiceUnits->SetSelection( 0 ); + fgSizer1->Add( m_choiceUnits, 0, wxALL|wxEXPAND, 3 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 3 ); + + m_staticText3 = new wxStaticText( m_panel1, wxID_ANY, _("&Grid size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + fgSizer1->Add( m_staticText3, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + wxArrayString m_choiceGridSizeChoices; + m_choiceGridSize = new wxChoice( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceGridSizeChoices, 0 ); + m_choiceGridSize->SetSelection( 0 ); + fgSizer1->Add( m_choiceGridSize, 0, wxEXPAND|wxALL, 3 ); + + m_staticGridUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticGridUnits->Wrap( -1 ); + fgSizer1->Add( m_staticGridUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText51 = new wxStaticText( m_panel1, wxID_ANY, _("&Default bus thickness:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText51->Wrap( -1 ); + fgSizer1->Add( m_staticText51, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinBusWidth = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 1, 100, 1 ); + fgSizer1->Add( m_spinBusWidth, 0, wxALL|wxEXPAND, 3 ); + + m_staticBusWidthUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticBusWidthUnits->Wrap( -1 ); + fgSizer1->Add( m_staticBusWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText5 = new wxStaticText( m_panel1, wxID_ANY, _("D&efault line thickness:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + fgSizer1->Add( m_staticText5, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinLineWidth = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 1, 100, 1 ); + fgSizer1->Add( m_spinLineWidth, 0, wxALL|wxEXPAND, 3 ); + + m_staticLineWidthUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticLineWidthUnits->Wrap( -1 ); + fgSizer1->Add( m_staticLineWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText7 = new wxStaticText( m_panel1, wxID_ANY, _("De&fault text size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText7->Wrap( -1 ); + fgSizer1->Add( m_staticText7, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinTextSize = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 0, 1000, 0 ); + fgSizer1->Add( m_spinTextSize, 0, wxALL|wxEXPAND, 3 ); + + m_staticTextSizeUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSizeUnits->Wrap( -1 ); + fgSizer1->Add( m_staticTextSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText9 = new wxStaticText( m_panel1, wxID_ANY, _("&Horizontal pitch of repeated items:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText9->Wrap( -1 ); + fgSizer1->Add( m_staticText9, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinRepeatHorizontal = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, -5000, 5000, 0 ); + fgSizer1->Add( m_spinRepeatHorizontal, 0, wxALL|wxEXPAND, 3 ); + + m_staticRepeatXUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticRepeatXUnits->Wrap( -1 ); + fgSizer1->Add( m_staticRepeatXUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText12 = new wxStaticText( m_panel1, wxID_ANY, _("&Vertical pitch of repeated items:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText12->Wrap( -1 ); + fgSizer1->Add( m_staticText12, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinRepeatVertical = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, -5000, 5000, 100 ); + fgSizer1->Add( m_spinRepeatVertical, 0, wxALL|wxEXPAND, 3 ); + + m_staticRepeatYUnits = new wxStaticText( m_panel1, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticRepeatYUnits->Wrap( -1 ); + fgSizer1->Add( m_staticRepeatYUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText16 = new wxStaticText( m_panel1, wxID_ANY, _("&Increment of repeated labels:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText16->Wrap( -1 ); + fgSizer1->Add( m_staticText16, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinRepeatLabel = new wxSpinCtrl( m_panel1, wxID_ANY, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, -10, 10, 1 ); + fgSizer1->Add( m_spinRepeatLabel, 0, wxALL|wxEXPAND, 3 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 3 ); + + m_staticText221 = new wxStaticText( m_panel1, wxID_ANY, _("&Auto-save time interval"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText221->Wrap( -1 ); + fgSizer1->Add( m_staticText221, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinAutoSaveInterval = new wxSpinCtrl( m_panel1, ID_M_SPINAUTOSAVEINTERVAL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 1000, 10 ); + fgSizer1->Add( m_spinAutoSaveInterval, 0, wxALL|wxEXPAND, 3 ); + + m_staticText23 = new wxStaticText( m_panel1, wxID_ANY, _("minutes"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText23->Wrap( -1 ); + fgSizer1->Add( m_staticText23, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_stMaxUndoItems = new wxStaticText( m_panel1, wxID_ANY, _("Ma&ximum undo items (0 = unlimited):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_stMaxUndoItems->Wrap( -1 ); + fgSizer1->Add( m_stMaxUndoItems, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_spinMaxUndoItems = new wxSpinCtrl( m_panel1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 65536, 0 ); + fgSizer1->Add( m_spinMaxUndoItems, 0, wxALL|wxEXPAND, 3 ); + + m_stMaxUndoItemsUnit = new wxStaticText( m_panel1, wxID_ANY, _("actions"), wxDefaultPosition, wxDefaultSize, 0 ); + m_stMaxUndoItemsUnit->Wrap( -1 ); + fgSizer1->Add( m_stMaxUndoItemsUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticText26 = new wxStaticText( m_panel1, wxID_ANY, _("&Part id notation:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText26->Wrap( -1 ); + fgSizer1->Add( m_staticText26, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 3 ); + + wxString m_choiceSeparatorRefIdChoices[] = { _("A"), _(".A"), _("-A"), _("_A"), _(".1"), _("-1"), _("_1") }; + int m_choiceSeparatorRefIdNChoices = sizeof( m_choiceSeparatorRefIdChoices ) / sizeof( wxString ); + m_choiceSeparatorRefId = new wxChoice( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceSeparatorRefIdNChoices, m_choiceSeparatorRefIdChoices, 0 ); + m_choiceSeparatorRefId->SetSelection( 0 ); + fgSizer1->Add( m_choiceSeparatorRefId, 0, wxALL|wxEXPAND, 3 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizer3->Add( fgSizer1, 0, wxEXPAND, 0 ); + + wxBoxSizer* bSizer2; + bSizer2 = new wxBoxSizer( wxVERTICAL ); + + m_staticline1 = new wxStaticLine( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizer2->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_checkShowGrid = new wxCheckBox( m_panel1, wxID_ANY, _("&Show grid"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkShowGrid, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkShowHiddenPins = new wxCheckBox( m_panel1, wxID_ANY, _("Sho&w hidden pins"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkShowHiddenPins, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkEnableZoomCenter = new wxCheckBox( m_panel1, wxID_ANY, _("Ce&nter and warp cursor on zoom"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkEnableZoomCenter->SetToolTip( _("Keep the cursor at its current location when zooming") ); + + bSizer2->Add( m_checkEnableZoomCenter, 0, wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkEnableMiddleButtonPan = new wxCheckBox( m_panel1, xwID_ANY, _("&Use middle mouse button to pan"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkEnableMiddleButtonPan->SetToolTip( _("Use middle mouse button dragging to pan") ); + + bSizer2->Add( m_checkEnableMiddleButtonPan, 0, wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkMiddleButtonPanLimited = new wxCheckBox( m_panel1, wxID_ANY, _("&Limit panning to scroll size"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkMiddleButtonPanLimited->SetToolTip( _("Middle mouse button panning limited by current scrollbar size") ); + + bSizer2->Add( m_checkMiddleButtonPanLimited, 0, wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkEnableMousewheelPan = new wxCheckBox( m_panel1, xwID_ANY, _("Use touchpa&d to pan"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkEnableMousewheelPan->SetToolTip( _("Use touchpad to pan canvas") ); + + bSizer2->Add( m_checkEnableMousewheelPan, 0, wxLEFT|wxRIGHT|wxTOP, 3 ); + + m_checkAutoPan = new wxCheckBox( m_panel1, wxID_ANY, _("Pan while moving ob&ject"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkAutoPan, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkHVOrientation = new wxCheckBox( m_panel1, wxID_ANY, _("&Restrict buses and wires to H and V orientation"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkHVOrientation, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 3 ); + + m_checkPageLimits = new wxCheckBox( m_panel1, wxID_ANY, _("Show page limi&ts"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkPageLimits, 0, wxALL|wxEXPAND, 3 ); + + + bSizer3->Add( bSizer2, 0, wxEXPAND, 0 ); + + + p1mainSizer->Add( bSizer3, 1, wxALL|wxEXPAND, 6 ); + + + m_panel1->SetSizer( p1mainSizer ); + m_panel1->Layout(); + p1mainSizer->Fit( m_panel1 ); + m_notebook->AddPage( m_panel1, _("General Options"), true ); + m_panel2 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panel2->SetToolTip( _("User defined field names for schematic components. ") ); + + wxBoxSizer* bSizer6; + bSizer6 = new wxBoxSizer( wxVERTICAL ); + + templateFieldListCtrl = new wxListView( m_panel2, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES ); + templateFieldListCtrl->SetMinSize( wxSize( 500,-1 ) ); + + bSizer6->Add( templateFieldListCtrl, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 8 ); + + wxStaticBoxSizer* fieldSizer; + fieldSizer = new wxStaticBoxSizer( new wxStaticBox( m_panel2, wxID_ANY, _("Field Settings") ), wxVERTICAL ); + + fieldNameLabel = new wxStaticText( fieldSizer->GetStaticBox(), wxID_ANY, _("&Name"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldNameLabel->Wrap( -1 ); + fieldSizer->Add( fieldNameLabel, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); + + fieldNameTextCtrl = new wxTextCtrl( fieldSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + fieldSizer->Add( fieldNameTextCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + fieldDefaultValueLabel = new wxStaticText( fieldSizer->GetStaticBox(), wxID_ANY, _("D&efault Value"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldDefaultValueLabel->Wrap( -1 ); + fieldSizer->Add( fieldDefaultValueLabel, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); + + fieldDefaultValueTextCtrl = new wxTextCtrl( fieldSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + fieldSizer->Add( fieldDefaultValueTextCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + fieldVisibleCheckbox = new wxCheckBox( fieldSizer->GetStaticBox(), wxID_ANY, _("&Visible"), wxDefaultPosition, wxDefaultSize, 0 ); + fieldSizer->Add( fieldVisibleCheckbox, 0, wxALL, 5 ); + + + bSizer6->Add( fieldSizer, 0, wxEXPAND, 5 ); + + addFieldButton = new wxButton( m_panel2, wxID_ADD_FIELD, _("&Add"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer6->Add( addFieldButton, 0, wxALL|wxEXPAND, 5 ); + + deleteFieldButton = new wxButton( m_panel2, wxID_DELETE_FIELD, _("&Delete"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer6->Add( deleteFieldButton, 0, wxALL|wxEXPAND, 5 ); + + + m_panel2->SetSizer( bSizer6 ); + m_panel2->Layout(); + bSizer6->Fit( m_panel2 ); + m_notebook->AddPage( m_panel2, _("Template Field Names"), false ); + + bOptionsSizer->Add( m_notebook, 1, wxALL|wxEXPAND, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + bOptionsSizer->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 6 ); + + + mainSizer->Add( bOptionsSizer, 1, wxEXPAND, 12 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + mainSizer->Fit( this ); + + this->Centre( wxBOTH ); +} + +DIALOG_EESCHEMA_OPTIONS_BASE::~DIALOG_EESCHEMA_OPTIONS_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_eeschema_options_base.fbp b/eeschema/dialogs/dialog_eeschema_options_base.fbp new file mode 100644 index 00000000..ed3cb317 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_options_base.fbp @@ -0,0 +1,4612 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + table + dialog_eeschema_options_base + 1000 + none + 1 + dialog_eeschema_options + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_EESCHEMA_OPTIONS_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Schematic Editor Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnSize + + + + mainSizer + wxVERTICAL + none + + 12 + wxEXPAND + 1 + + + bOptionsSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + wxSYS_COLOUR_BTNFACE + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_notebook + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + General Options + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel1 + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + p1mainSizer + wxHORIZONTAL + none + + 6 + wxALL|wxEXPAND + 1 + + + bSizer3 + wxVERTICAL + none + + 0 + wxEXPAND + 0 + + 3 + wxBOTH + 0,1,2 + + 0 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Measurement units: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceUnits + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnChooseUnits + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Grid size: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceGridSize + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticGridUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Default bus thickness: + + 0 + + + 0 + + 1 + m_staticText51 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 1 + 100 + + 0 + + 1 + + 0 + + 1 + m_spinBusWidth + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticBusWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + D&efault line thickness: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 1 + 100 + + 0 + + 1 + + 0 + + 1 + m_spinLineWidth + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticLineWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + De&fault text size: + + 0 + + + 0 + + 1 + m_staticText7 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 1000 + + 0 + + 0 + + 0 + + 1 + m_spinTextSize + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticTextSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Horizontal pitch of repeated items: + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 5000 + + 0 + + -5000 + + 0 + + 1 + m_spinRepeatHorizontal + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticRepeatXUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Vertical pitch of repeated items: + + 0 + + + 0 + + 1 + m_staticText12 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 100 + 5000 + + 0 + + -5000 + + 0 + + 1 + m_spinRepeatVertical + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticRepeatYUnits + 1 + + + protected + 1 + + Fixed + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Increment of repeated labels: + + 0 + + + 0 + + 1 + m_staticText16 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 1 + 10 + + 0 + + -10 + + 0 + + 1 + m_spinRepeatLabel + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Auto-save time interval + + 0 + + + 0 + + 1 + m_staticText221 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_SPINAUTOSAVEINTERVAL + 10 + 1000 + + 0 + + 0 + + 0 + + 1 + m_spinAutoSaveInterval + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + minutes + + 0 + + + 0 + + 1 + m_staticText23 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Ma&ximum undo items (0 = unlimited): + + 0 + + + 0 + + 1 + m_stMaxUndoItems + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 65536 + + 0 + + 0 + + 0 + + 1 + m_spinMaxUndoItems + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + actions + + 0 + + + 0 + + 1 + m_stMaxUndoItemsUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Part id notation: + + 0 + + + 0 + + 1 + m_staticText26 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "A" ".A" "-A" "_A" ".1" "-1" "_1" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceSeparatorRefId + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 0 + wxEXPAND + 0 + + + bSizer2 + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Show grid + + 0 + + + 0 + + 1 + m_checkShowGrid + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Sho&w hidden pins + + 0 + + + 0 + + 1 + m_checkShowHiddenPins + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Ce&nter and warp cursor on zoom + + 0 + + + 0 + + 1 + m_checkEnableZoomCenter + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Keep the cursor at its current location when zooming + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + xwID_ANY + &Use middle mouse button to pan + + 0 + + + 0 + + 1 + m_checkEnableMiddleButtonPan + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Use middle mouse button dragging to pan + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnMiddleBtnPanEnbl + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Limit panning to scroll size + + 0 + + + 0 + + 1 + m_checkMiddleButtonPanLimited + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Middle mouse button panning limited by current scrollbar size + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + xwID_ANY + Use touchpa&d to pan + + 0 + + + 0 + + 1 + m_checkEnableMousewheelPan + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Use touchpad to pan canvas + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pan while moving ob&ject + + 0 + + + 0 + + 1 + m_checkAutoPan + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Restrict buses and wires to H and V orientation + + 0 + + + 0 + + 1 + m_checkHVOrientation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show page limi&ts + + 0 + + + 0 + + 1 + m_checkPageLimits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Template Field Names + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel2 + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + User defined field names for schematic components. + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer6 + wxVERTICAL + none + + 8 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 500,-1 + 1 + templateFieldListCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES + wxListView; + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnTemplateFieldDeselected + + + + OnTemplateFieldSelected + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + wxID_ANY + Field Settings + + fieldSizer + wxVERTICAL + 1 + none + + + 5 + wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Name + + 0 + + + 0 + + 1 + fieldNameLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldNameTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnEnterKey + + + + + + + 5 + wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + D&efault Value + + 0 + + + 0 + + 1 + fieldDefaultValueLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + fieldDefaultValueTextCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnEnterKey + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Visible + + 0 + + + 0 + + 1 + fieldVisibleCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnVisibleFieldClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ADD_FIELD + &Add + + 0 + + + 0 + + 1 + addFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddButtonClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_DELETE_FIELD + &Delete + + 0 + + + 0 + + 1 + deleteFieldButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnDeleteButtonClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_eeschema_options_base.h b/eeschema/dialogs/dialog_eeschema_options_base.h new file mode 100644 index 00000000..911a7475 --- /dev/null +++ b/eeschema/dialogs/dialog_eeschema_options_base.h @@ -0,0 +1,145 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_EESCHEMA_OPTIONS_BASE_H__ +#define __DIALOG_EESCHEMA_OPTIONS_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; +class wxListView; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_EESCHEMA_OPTIONS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_EESCHEMA_OPTIONS_BASE : public DIALOG_SHIM +{ + DECLARE_EVENT_TABLE() + private: + + // Private event handlers + void _wxFB_OnSize( wxSizeEvent& event ){ OnSize( event ); } + void _wxFB_OnChooseUnits( wxCommandEvent& event ){ OnChooseUnits( event ); } + void _wxFB_OnMiddleBtnPanEnbl( wxCommandEvent& event ){ OnMiddleBtnPanEnbl( event ); } + void _wxFB_OnTemplateFieldDeselected( wxListEvent& event ){ OnTemplateFieldDeselected( event ); } + void _wxFB_OnTemplateFieldSelected( wxListEvent& event ){ OnTemplateFieldSelected( event ); } + void _wxFB_OnEnterKey( wxCommandEvent& event ){ OnEnterKey( event ); } + void _wxFB_OnVisibleFieldClick( wxCommandEvent& event ){ OnVisibleFieldClick( event ); } + void _wxFB_OnAddButtonClick( wxCommandEvent& event ){ OnAddButtonClick( event ); } + void _wxFB_OnDeleteButtonClick( wxCommandEvent& event ){ OnDeleteButtonClick( event ); } + + + protected: + enum + { + ID_M_SPINAUTOSAVEINTERVAL = 1000, + xwID_ANY, + wxID_ADD_FIELD, + wxID_DELETE_FIELD + }; + + wxNotebook* m_notebook; + wxPanel* m_panel1; + wxStaticText* m_staticText2; + wxChoice* m_choiceUnits; + wxStaticText* m_staticText3; + wxChoice* m_choiceGridSize; + wxStaticText* m_staticGridUnits; + wxStaticText* m_staticText51; + wxSpinCtrl* m_spinBusWidth; + wxStaticText* m_staticBusWidthUnits; + wxStaticText* m_staticText5; + wxSpinCtrl* m_spinLineWidth; + wxStaticText* m_staticLineWidthUnits; + wxStaticText* m_staticText7; + wxSpinCtrl* m_spinTextSize; + wxStaticText* m_staticTextSizeUnits; + wxStaticText* m_staticText9; + wxSpinCtrl* m_spinRepeatHorizontal; + wxStaticText* m_staticRepeatXUnits; + wxStaticText* m_staticText12; + wxSpinCtrl* m_spinRepeatVertical; + wxStaticText* m_staticRepeatYUnits; + wxStaticText* m_staticText16; + wxSpinCtrl* m_spinRepeatLabel; + wxStaticText* m_staticText221; + wxSpinCtrl* m_spinAutoSaveInterval; + wxStaticText* m_staticText23; + wxStaticText* m_stMaxUndoItems; + wxSpinCtrl* m_spinMaxUndoItems; + wxStaticText* m_stMaxUndoItemsUnit; + wxStaticText* m_staticText26; + wxChoice* m_choiceSeparatorRefId; + wxStaticLine* m_staticline1; + wxCheckBox* m_checkShowGrid; + wxCheckBox* m_checkShowHiddenPins; + wxCheckBox* m_checkEnableZoomCenter; + wxCheckBox* m_checkEnableMiddleButtonPan; + wxCheckBox* m_checkMiddleButtonPanLimited; + wxCheckBox* m_checkEnableMousewheelPan; + wxCheckBox* m_checkAutoPan; + wxCheckBox* m_checkHVOrientation; + wxCheckBox* m_checkPageLimits; + wxPanel* m_panel2; + wxListView* templateFieldListCtrl; + wxStaticText* fieldNameLabel; + wxTextCtrl* fieldNameTextCtrl; + wxStaticText* fieldDefaultValueLabel; + wxTextCtrl* fieldDefaultValueTextCtrl; + wxCheckBox* fieldVisibleCheckbox; + wxButton* addFieldButton; + wxButton* deleteFieldButton; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnSize( wxSizeEvent& event ) { event.Skip(); } + virtual void OnChooseUnits( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMiddleBtnPanEnbl( wxCommandEvent& event ) { event.Skip(); } + virtual void OnTemplateFieldDeselected( wxListEvent& event ) { event.Skip(); } + virtual void OnTemplateFieldSelected( wxListEvent& event ) { event.Skip(); } + virtual void OnEnterKey( wxCommandEvent& event ) { event.Skip(); } + virtual void OnVisibleFieldClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDeleteButtonClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_EESCHEMA_OPTIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Schematic Editor Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_EESCHEMA_OPTIONS_BASE(); + +}; + +#endif //__DIALOG_EESCHEMA_OPTIONS_BASE_H__ diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp new file mode 100644 index 00000000..f1f28c04 --- /dev/null +++ b/eeschema/dialogs/dialog_erc.cpp @@ -0,0 +1,579 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2012 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file dialog_erc.cpp + * @brief Electrical Rules Check dialog implementation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +bool DIALOG_ERC::m_writeErcFile = false; + + +BEGIN_EVENT_TABLE( DIALOG_ERC, DIALOG_ERC_BASE ) + EVT_COMMAND_RANGE( ID_MATRIX_0, ID_MATRIX_0 + ( PIN_NMAX * PIN_NMAX ) - 1, + wxEVT_COMMAND_BUTTON_CLICKED, DIALOG_ERC::ChangeErrorLevel ) +END_EVENT_TABLE() + + +DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) : + DIALOG_ERC_BASE( parent, ID_DIALOG_ERC // parent looks for this ID explicitly + ) +{ + m_parent = parent; + m_lastMarkerFound = NULL; + Init(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + +DIALOG_ERC::~DIALOG_ERC() +{ +} + + +void DIALOG_ERC::Init() +{ + m_initialized = false; + + for( int ii = 0; ii < PIN_NMAX; ii++ ) + { + for( int jj = 0; jj < PIN_NMAX; jj++ ) + m_buttonList[ii][jj] = NULL; + } + + m_WriteResultOpt->SetValue( m_writeErcFile ); + + SCH_SCREENS screens; + updateMarkerCounts( &screens ); + + DisplayERC_MarkersList(); + + // Init Panel Matrix + ReBuildMatrixPanel(); + + // Set the run ERC button as the default button. + m_buttonERC->SetDefault(); +} + + +void DIALOG_ERC::updateMarkerCounts( SCH_SCREENS *screens ) +{ + int markers = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC, + MARKER_BASE::MARKER_SEVERITY_UNSPEC ); + int warnings = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC, + MARKER_BASE::MARKER_SEVERITY_WARNING ); + int errors = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC, + MARKER_BASE::MARKER_SEVERITY_ERROR ); + + wxString num; + num.Printf( wxT( "%d" ), markers ); + m_TotalErrCount->SetValue( num ); + + num.Printf( wxT( "%d" ), errors ); + m_LastErrCount->SetValue( num ); + + num.Printf( wxT( "%d" ), warnings ); + m_LastWarningCount->SetValue( num ); +} + + +/* Delete the old ERC markers, over the whole hierarchy + */ +void DIALOG_ERC::OnEraseDrcMarkersClick( wxCommandEvent& event ) +{ + SCH_SCREENS ScreenList; + + ScreenList.DeleteAllMarkers( MARKER_BASE::MARKER_ERC ); + updateMarkerCounts( &ScreenList ); + + m_MarkersList->ClearList(); + m_parent->GetCanvas()->Refresh(); +} + + + +/* event handler for Close button +*/ +void DIALOG_ERC::OnButtonCloseClick( wxCommandEvent& event ) +{ + Close(); +} + +void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& event ) +{ + Destroy(); +} + + +void DIALOG_ERC::OnResetMatrixClick( wxCommandEvent& event ) +{ + ResetDefaultERCDiag( event ); +} + + +void DIALOG_ERC::OnErcCmpClick( wxCommandEvent& event ) +{ + wxBusyCursor(); + m_MarkersList->ClearList(); + + m_MessagesList->Clear(); + wxSafeYield(); // m_MarkersList must be redraw + wxArrayString messageList; + TestErc( &messageList ); + + for( unsigned ii = 0; ii < messageList.GetCount(); ii++ ) + m_MessagesList->AppendText( messageList[ii] ); +} + + +void DIALOG_ERC::OnLeftClickMarkersList( wxHtmlLinkEvent& event ) +{ + wxString link = event.GetLinkInfo().GetHref(); + + m_lastMarkerFound = NULL; + + long index; + + if( !link.ToLong( &index ) ) + return; + + const SCH_MARKER* marker = m_MarkersList->GetItem( index ); + + if( marker == NULL ) + return; + + // Search for the selected marker + SCH_SHEET_PATH* sheet; + SCH_SHEET_LIST SheetList; + bool notFound = true; + + for( sheet = SheetList.GetFirst(); sheet; sheet = SheetList.GetNext() ) + { + SCH_ITEM* item = (SCH_ITEM*) sheet->LastDrawList(); + + for( ; item; item = item->Next() ) + { + if( item == marker ) + { + notFound = false; + break; + } + } + + if( notFound == false ) + break; + } + + if( notFound ) // Error + { + wxMessageBox( _( "Marker not found" ) ); + + // The marker was deleted, so rebuild marker list + DisplayERC_MarkersList(); + return; + } + + if( *sheet != m_parent->GetCurrentSheet() ) + { + sheet->LastScreen()->SetZoom( m_parent->GetScreen()->GetZoom() ); + m_parent->SetCurrentSheet( *sheet ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + } + + m_lastMarkerFound = marker; + m_parent->SetCrossHairPosition( marker->m_Pos ); + m_parent->RedrawScreen( marker->m_Pos, false); +} + + +void DIALOG_ERC::OnLeftDblClickMarkersList( wxMouseEvent& event ) +{ + // Remember: OnLeftClickMarkersList was called just berfore + // and therefore m_lastMarkerFound was initialized. + // (NULL if not found) + if( m_lastMarkerFound ) + { + m_parent->SetCrossHairPosition( m_lastMarkerFound->m_Pos ); + m_parent->RedrawScreen( m_lastMarkerFound->m_Pos, true ); + // prevent a mouse left button release event in + // coming from the ERC dialog double click + // ( the button is released after closing this dialog and will generate + // an unwanted event in parent frame) + m_parent->SkipNextLeftButtonReleaseEvent(); + } + + Close(); +} + + +void DIALOG_ERC::ReBuildMatrixPanel() +{ + // Try to know the size of bitmap button used in drc matrix + wxBitmapButton * dummy = new wxBitmapButton( m_matrixPanel, wxID_ANY, KiBitmap( ercerr_xpm ) ); + wxSize bitmap_size = dummy->GetSize(); + delete dummy; + + if( !DiagErcTableInit ) + { + memcpy( DiagErc, DefaultDiagErc, sizeof(DefaultDiagErc) ); + DiagErcTableInit = true; + } + + wxPoint pos; + // Get the current text size:use a dummy text. + wxStaticText* text = new wxStaticText( m_matrixPanel, -1, wxT( "W" ), pos ); + int text_height = text->GetRect().GetHeight(); + bitmap_size.y = std::max( bitmap_size.y, text_height ); + delete text; + + // compute the Y pos interval: + pos.y = text_height; + + if( m_initialized == false ) + { + // Print row labels + for( int ii = 0; ii < PIN_NMAX; ii++ ) + { + int y = pos.y + (ii * bitmap_size.y); + text = new wxStaticText( m_matrixPanel, -1, CommentERC_H[ii], + wxPoint( 5, y + ( bitmap_size.y / 2) - (text_height / 2) ) ); + + int x = text->GetRect().GetRight(); + pos.x = std::max( pos.x, x ); + } + + pos.x += 5; + } + else + pos = m_buttonList[0][0]->GetPosition(); + + for( int ii = 0; ii < PIN_NMAX; ii++ ) + { + int y = pos.y + (ii * bitmap_size.y); + + for( int jj = 0; jj <= ii; jj++ ) + { + // Add column labels (only once) + int diag = DiagErc[ii][jj]; + int x = pos.x + (jj * bitmap_size.x); + + if( (ii == jj) && !m_initialized ) + { + wxPoint txtpos; + txtpos.x = x + (bitmap_size.x / 2); + txtpos.y = y - text_height; + text = new wxStaticText( m_matrixPanel, -1, CommentERC_V[ii], txtpos ); + } + + int event_id = ID_MATRIX_0 + ii + ( jj * PIN_NMAX ); + BITMAP_DEF bitmap_butt = erc_green_xpm; + + delete m_buttonList[ii][jj]; + m_buttonList[ii][jj] = new wxBitmapButton( m_matrixPanel, + event_id, + KiBitmap( bitmap_butt ), + wxPoint( x, y ) ); + setDRCMatrixButtonState( m_buttonList[ii][jj], diag ); + } + } + + m_initialized = true; +} + + +void DIALOG_ERC::setDRCMatrixButtonState( wxBitmapButton *aButton, int aState ) +{ + BITMAP_DEF bitmap_butt = NULL; + wxString tooltip; + + switch( aState ) + { + case OK: + bitmap_butt = erc_green_xpm; + tooltip = _( "No error or warning" ); + break; + + case WAR: + bitmap_butt = ercwarn_xpm; + tooltip = _( "Generate warning" ); + break; + + case ERR: + bitmap_butt = ercerr_xpm; + tooltip = _( "Generate error" ); + break; + } + + if( bitmap_butt ) + { + aButton->SetBitmap( KiBitmap( bitmap_butt ) ); + aButton->SetToolTip( tooltip ); + } +} + + +void DIALOG_ERC::DisplayERC_MarkersList() +{ + SCH_SHEET_LIST sheetList; + m_MarkersList->ClearList(); + + SCH_SHEET_PATH* sheet = sheetList.GetFirst(); + + for( ; sheet != NULL; sheet = sheetList.GetNext() ) + { + SCH_ITEM* item = sheet->LastDrawList(); + + for( ; item != NULL; item = item->Next() ) + { + if( item->Type() != SCH_MARKER_T ) + continue; + + SCH_MARKER* marker = (SCH_MARKER*) item; + + if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC ) + continue; + + m_MarkersList->AppendToList( marker ); + } + } + + m_MarkersList->DisplayList(); +} + + +void DIALOG_ERC::ResetDefaultERCDiag( wxCommandEvent& event ) +{ + memcpy( DiagErc, DefaultDiagErc, sizeof( DiagErc ) ); + ReBuildMatrixPanel(); +} + + +void DIALOG_ERC::ChangeErrorLevel( wxCommandEvent& event ) +{ + int id, level, ii, x, y; + wxPoint pos; + + id = event.GetId(); + ii = id - ID_MATRIX_0; + wxBitmapButton* butt = (wxBitmapButton*) event.GetEventObject(); + pos = butt->GetPosition(); + + x = ii / PIN_NMAX; y = ii % PIN_NMAX; + + level = DiagErc[y][x]; + + //change to the next error level + switch( level ) + { + case OK: + level = WAR; + break; + + case WAR: + level = ERR; + break; + + case ERR: + level = OK; + break; + } + + setDRCMatrixButtonState( butt, level); + + DiagErc[y][x] = DiagErc[x][y] = level; +} + + +void DIALOG_ERC::TestErc( wxArrayString* aMessagesList ) +{ + wxFileName fn; + + if( !DiagErcTableInit ) + { + memcpy( DiagErc, DefaultDiagErc, sizeof( DefaultDiagErc ) ); + DiagErcTableInit = true; + } + + m_writeErcFile = m_WriteResultOpt->GetValue(); + + // Build the whole sheet list in hierarchy (sheet, not screen) + SCH_SHEET_LIST sheets; + sheets.AnnotatePowerSymbols( Prj().SchLibs() ); + + if( m_parent->CheckAnnotate( aMessagesList, false ) ) + { + if( aMessagesList ) + { + wxString msg = _( "Annotation required!" ); + msg += wxT( "\n" ); + aMessagesList->Add( msg ); + } + + return; + } + + SCH_SCREENS screens; + + // Erase all previous DRC markers. + screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC ); + + for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() ) + { + /* Ff wire list has changed, delete Undo Redo list to avoid pointers on deleted + * data problems. + */ + if( screen->SchematicCleanUp( NULL ) ) + screen->ClearUndoRedoList(); + } + + /* Test duplicate sheet names inside a given sheet, one cannot have sheets with + * duplicate names (file names can be duplicated). + */ + TestDuplicateSheetNames( true ); + + std::auto_ptr objectsConnectedList( m_parent->BuildNetListBase() ); + + // Reset the connection type indicator + objectsConnectedList->ResetConnectionsType(); + + unsigned lastNet; + unsigned nextNet = lastNet = 0; + int MinConn = NOC; + + for( unsigned net = 0; net < objectsConnectedList->size(); net++ ) + { + if( objectsConnectedList->GetItemNet( lastNet ) != + objectsConnectedList->GetItemNet( net ) ) + { + // New net found: + MinConn = NOC; + nextNet = net; + } + + switch( objectsConnectedList->GetItemType( net ) ) + { + // These items do not create erc problems + case NET_ITEM_UNSPECIFIED: + case NET_SEGMENT: + case NET_BUS: + case NET_JUNCTION: + case NET_LABEL: + case NET_BUSLABELMEMBER: + case NET_PINLABEL: + case NET_GLOBBUSLABELMEMBER: + break; + + case NET_HIERLABEL: + case NET_HIERBUSLABELMEMBER: + case NET_SHEETLABEL: + case NET_SHEETBUSLABELMEMBER: + case NET_GLOBLABEL: + + // ERC problems when pin sheets do not match hierarchical labels. + // Each pin sheet must match a hierarchical label + // Each hierarchical label must match a pin sheet + TestLabel( objectsConnectedList.get(), net, nextNet ); + break; + + case NET_NOCONNECT: + + // ERC problems when a noconnect symbol is connected to more than one pin. + MinConn = NET_NC; + + if( CountPinsInNet( objectsConnectedList.get(), nextNet ) > 1 ) + Diagnose( objectsConnectedList->GetItem( net ), NULL, MinConn, UNC ); + + break; + + case NET_PIN: + + // Look for ERC problems between pins: + TestOthersItems( objectsConnectedList.get(), net, nextNet, &MinConn ); + break; + } + + lastNet = net; + } + + // Displays global results: + updateMarkerCounts( &screens ); + + // Display diags: + DisplayERC_MarkersList(); + + // Display new markers: + m_parent->GetCanvas()->Refresh(); + + if( m_writeErcFile ) + { + fn = g_RootSheet->GetScreen()->GetFileName(); + fn.SetExt( wxT( "erc" ) ); + + wxFileDialog dlg( this, _( "ERC File" ), fn.GetPath(), fn.GetFullName(), + _( "Electronic rule check file (.erc)|*.erc" ), + wxFD_SAVE ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + if( WriteDiagnosticERC( dlg.GetPath() ) ) + ExecuteFile( this, Pgm().GetEditorName(), QuoteFullPath( fn ) ); + } +} + + +wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller ) +{ + // This is a modeless dialog, so new it rather than instantiating on stack. + DIALOG_ERC* dlg = new DIALOG_ERC( aCaller ); + + dlg->Show( true ); + + return dlg; // wxDialog is information hiding about DIALOG_ERC. +} diff --git a/eeschema/dialogs/dialog_erc.h b/eeschema/dialogs/dialog_erc.h new file mode 100644 index 00000000..e086166c --- /dev/null +++ b/eeschema/dialogs/dialog_erc.h @@ -0,0 +1,92 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2014 KiCad Developers, see CHANGELOG.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_ERC_H_ +#define _DIALOG_ERC_H_ + +#include +#include + + +#include +#include "dialog_erc_listbox.h" + +/* Variable locales */ +extern int DiagErc[PIN_NMAX][PIN_NMAX]; +extern bool DiagErcTableInit; // go to true after DiagErc init +extern int DefaultDiagErc[PIN_NMAX][PIN_NMAX]; + +/* Control identifiers */ +#define ID_MATRIX_0 1800 + +/*! + * DIALOG_ERC class declaration + */ + +class DIALOG_ERC : public DIALOG_ERC_BASE +{ + DECLARE_EVENT_TABLE() + +private: + SCH_EDIT_FRAME* m_parent; + wxBitmapButton* m_buttonList[PIN_NMAX][PIN_NMAX]; + bool m_initialized; + const SCH_MARKER* m_lastMarkerFound; + static bool m_writeErcFile; + +public: + DIALOG_ERC( SCH_EDIT_FRAME* parent ); + ~DIALOG_ERC(); + +private: + void Init(); + + // from DIALOG_ERC_BASE: + void OnCloseErcDialog( wxCloseEvent& event ); + void OnErcCmpClick( wxCommandEvent& event ); + void OnEraseDrcMarkersClick( wxCommandEvent& event ); + void OnButtonCloseClick( wxCommandEvent& event ); + void OnResetMatrixClick( wxCommandEvent& event ); + + // Click on a marker info: + void OnLeftClickMarkersList( wxHtmlLinkEvent& event ); + + // Double click on a marker info: + void OnLeftDblClickMarkersList( wxMouseEvent& event ); + + void TestErc( wxArrayString* aMessagesList ); + void DisplayERC_MarkersList(); + void SelLocal( wxCommandEvent& event ); + void SelNewCmp( wxCommandEvent& event ); + void ResetDefaultERCDiag( wxCommandEvent& event ); + void ChangeErrorLevel( wxCommandEvent& event ); + void ReBuildMatrixPanel(); + void setDRCMatrixButtonState( wxBitmapButton *aButton, int aState ); + void updateMarkerCounts( SCH_SCREENS *screens ); +}; + + +#endif + +// _DIALOG_ERC_H_ diff --git a/eeschema/dialogs/dialog_erc_base.cpp b/eeschema/dialogs/dialog_erc_base.cpp new file mode 100644 index 00000000..c1ef861b --- /dev/null +++ b/eeschema/dialogs/dialog_erc_base.cpp @@ -0,0 +1,152 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 17 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_erc_listbox.h" + +#include "dialog_erc_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_ERC_BASE::DIALOG_ERC_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizer1; + bSizer1 = new wxBoxSizer( wxVERTICAL ); + + m_NoteBook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_PanelERC = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bercSizer; + bercSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bupperSizer; + bupperSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticBoxSizer* sdiagSizer; + sdiagSizer = new wxStaticBoxSizer( new wxStaticBox( m_PanelERC, wxID_ANY, _("ERC Report:") ), wxVERTICAL ); + + wxGridSizer* gSizeDiag; + gSizeDiag = new wxGridSizer( 3, 2, 0, 0 ); + + m_ErcTotalErrorsText = new wxStaticText( sdiagSizer->GetStaticBox(), wxID_ANY, _("Total:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ErcTotalErrorsText->Wrap( -1 ); + gSizeDiag->Add( m_ErcTotalErrorsText, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_TotalErrCount = new wxTextCtrl( sdiagSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + gSizeDiag->Add( m_TotalErrCount, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_WarnErcErrorsText = new wxStaticText( sdiagSizer->GetStaticBox(), wxID_ANY, _("Warnings:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_WarnErcErrorsText->Wrap( -1 ); + gSizeDiag->Add( m_WarnErcErrorsText, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_LastWarningCount = new wxTextCtrl( sdiagSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + gSizeDiag->Add( m_LastWarningCount, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_LastErrCountText = new wxStaticText( sdiagSizer->GetStaticBox(), wxID_ANY, _("Errors:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_LastErrCountText->Wrap( -1 ); + gSizeDiag->Add( m_LastErrCountText, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_LastErrCount = new wxTextCtrl( sdiagSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + gSizeDiag->Add( m_LastErrCount, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + sdiagSizer->Add( gSizeDiag, 0, wxEXPAND, 5 ); + + m_WriteResultOpt = new wxCheckBox( sdiagSizer->GetStaticBox(), wxID_ANY, _("Create ERC file report"), wxDefaultPosition, wxDefaultSize, 0 ); + sdiagSizer->Add( m_WriteResultOpt, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + + bupperSizer->Add( sdiagSizer, 0, wxEXPAND|wxTOP, 5 ); + + wxBoxSizer* bSizerMessages; + bSizerMessages = new wxBoxSizer( wxVERTICAL ); + + m_titleMessages = new wxStaticText( m_PanelERC, wxID_ANY, _("Messages:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_titleMessages->Wrap( -1 ); + bSizerMessages->Add( m_titleMessages, 0, wxRIGHT|wxLEFT, 5 ); + + m_MessagesList = new wxTextCtrl( m_PanelERC, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY ); + bSizerMessages->Add( m_MessagesList, 1, wxEXPAND|wxLEFT, 5 ); + + + bupperSizer->Add( bSizerMessages, 1, wxEXPAND, 5 ); + + + bercSizer->Add( bupperSizer, 0, wxALL|wxEXPAND, 5 ); + + m_textMarkers = new wxStaticText( m_PanelERC, wxID_ANY, _("Error list:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_textMarkers->Wrap( -1 ); + bercSizer->Add( m_textMarkers, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_MarkersList = new ERC_HTML_LISTFRAME( m_PanelERC, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO|wxSUNKEN_BORDER ); + bercSizer->Add( m_MarkersList, 1, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bbuttonsSizer; + bbuttonsSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_buttondelmarkers = new wxButton( m_PanelERC, ID_ERASE_DRC_MARKERS, _("&Delete Markers"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttondelmarkers, 0, wxALL|wxEXPAND, 5 ); + + m_buttonERC = new wxButton( m_PanelERC, ID_ERC_CMP, _("&Run"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonERC->SetDefault(); + bbuttonsSizer->Add( m_buttonERC, 0, wxALL|wxEXPAND, 5 ); + + m_buttonClose = new wxButton( m_PanelERC, wxID_CANCEL, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttonClose, 0, wxALL|wxEXPAND, 5 ); + + + bercSizer->Add( bbuttonsSizer, 0, wxALIGN_RIGHT, 5 ); + + + m_PanelERC->SetSizer( bercSizer ); + m_PanelERC->Layout(); + bercSizer->Fit( m_PanelERC ); + m_NoteBook->AddPage( m_PanelERC, _("ERC"), true ); + m_PanelERCOptions = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* m_panelMatrixSizer; + m_panelMatrixSizer = new wxBoxSizer( wxVERTICAL ); + + m_ResetOptButton = new wxButton( m_PanelERCOptions, ID_RESET_MATRIX, _("Initialize to Default"), wxDefaultPosition, wxDefaultSize, 0 ); + m_panelMatrixSizer->Add( m_ResetOptButton, 0, wxALIGN_RIGHT|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_matrixPanel = new wxPanel( m_PanelERCOptions, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelMatrixSizer->Add( m_matrixPanel, 1, wxEXPAND | wxALL, 5 ); + + + m_PanelERCOptions->SetSizer( m_panelMatrixSizer ); + m_PanelERCOptions->Layout(); + m_panelMatrixSizer->Fit( m_PanelERCOptions ); + m_NoteBook->AddPage( m_PanelERCOptions, _("Options"), false ); + + bSizer1->Add( m_NoteBook, 1, wxEXPAND | wxALL, 5 ); + + + this->SetSizer( bSizer1 ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) ); + m_MarkersList->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLeftClickMarkersList ), NULL, this ); + m_MarkersList->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_ERC_BASE::OnLeftDblClickMarkersList ), NULL, this ); + m_buttondelmarkers->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnEraseDrcMarkersClick ), NULL, this ); + m_buttonERC->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnErcCmpClick ), NULL, this ); + m_buttonClose->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnButtonCloseClick ), NULL, this ); + m_ResetOptButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnResetMatrixClick ), NULL, this ); +} + +DIALOG_ERC_BASE::~DIALOG_ERC_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) ); + m_MarkersList->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLeftClickMarkersList ), NULL, this ); + m_MarkersList->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_ERC_BASE::OnLeftDblClickMarkersList ), NULL, this ); + m_buttondelmarkers->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnEraseDrcMarkersClick ), NULL, this ); + m_buttonERC->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnErcCmpClick ), NULL, this ); + m_buttonClose->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnButtonCloseClick ), NULL, this ); + m_ResetOptButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnResetMatrixClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_erc_base.fbp b/eeschema/dialogs/dialog_erc_base.fbp new file mode 100644 index 00000000..aa6589a1 --- /dev/null +++ b/eeschema/dialogs/dialog_erc_base.fbp @@ -0,0 +1,1799 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_erc_base + 1000 + none + 1 + dialog_ERC_base + + . + + 0 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_ERC_BASE + + 519,457 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Electrical Rules Checker + + + + + + + + + + + + + + OnCloseErcDialog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer1 + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_NoteBook + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ERC + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelERC + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bercSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + + bupperSizer + wxHORIZONTAL + none + + 5 + wxEXPAND|wxTOP + 0 + + wxID_ANY + ERC Report: + + sdiagSizer + wxVERTICAL + none + + + 5 + wxEXPAND + 0 + + 2 + 0 + + gSizeDiag + none + 3 + 0 + + 5 + wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Total: + + 0 + + + 0 + + 1 + m_ErcTotalErrorsText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_TotalErrCount + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Warnings: + + 0 + + + 0 + + 1 + m_WarnErcErrorsText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_LastWarningCount + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Errors: + + 0 + + + 0 + + 1 + m_LastErrCountText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_LastErrCount + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Create ERC file report + + 0 + + + 0 + + 1 + m_WriteResultOpt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerMessages + wxVERTICAL + none + + 5 + wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Messages: + + 0 + + + 0 + + 1 + m_titleMessages + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + -1,-1 + 1 + m_MessagesList + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_MULTILINE|wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Error list: + + 0 + + + 0 + + 1 + m_textMarkers + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_MarkersList + 1 + + + protected + 1 + + Resizable + 1 + + wxHW_SCROLLBAR_AUTO + ERC_HTML_LISTFRAME; dialog_erc_listbox.h + 0 + + + + wxSUNKEN_BORDER + + + + + + OnLeftClickMarkersList + + + + + OnLeftDblClickMarkersList + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bbuttonsSizer + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ERASE_DRC_MARKERS + &Delete Markers + + 0 + + + 0 + + 1 + m_buttondelmarkers + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnEraseDrcMarkersClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ERC_CMP + &Run + + 0 + + + 0 + + 1 + m_buttonERC + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnErcCmpClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + &Close + + 0 + + + 0 + + 1 + m_buttonClose + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonCloseClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Options + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_PanelERCOptions + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + m_panelMatrixSizer + wxVERTICAL + none + + 5 + wxALIGN_RIGHT|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_RESET_MATRIX + Initialize to Default + + 0 + + + 0 + + 1 + m_ResetOptButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnResetMatrixClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_matrixPanel + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_erc_base.h b/eeschema/dialogs/dialog_erc_base.h new file mode 100644 index 00000000..007f9462 --- /dev/null +++ b/eeschema/dialogs/dialog_erc_base.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 17 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_ERC_BASE_H__ +#define __DIALOG_ERC_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; +class ERC_HTML_LISTFRAME; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define ID_ERASE_DRC_MARKERS 1000 +#define ID_ERC_CMP 1001 +#define ID_RESET_MATRIX 1002 + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_ERC_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_ERC_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxNotebook* m_NoteBook; + wxPanel* m_PanelERC; + wxStaticText* m_ErcTotalErrorsText; + wxTextCtrl* m_TotalErrCount; + wxStaticText* m_WarnErcErrorsText; + wxTextCtrl* m_LastWarningCount; + wxStaticText* m_LastErrCountText; + wxTextCtrl* m_LastErrCount; + wxCheckBox* m_WriteResultOpt; + wxStaticText* m_titleMessages; + wxTextCtrl* m_MessagesList; + wxStaticText* m_textMarkers; + ERC_HTML_LISTFRAME* m_MarkersList; + wxButton* m_buttondelmarkers; + wxButton* m_buttonERC; + wxButton* m_buttonClose; + wxPanel* m_PanelERCOptions; + wxButton* m_ResetOptButton; + wxPanel* m_matrixPanel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseErcDialog( wxCloseEvent& event ) { event.Skip(); } + virtual void OnLeftClickMarkersList( wxHtmlLinkEvent& event ) { event.Skip(); } + virtual void OnLeftDblClickMarkersList( wxMouseEvent& event ) { event.Skip(); } + virtual void OnEraseDrcMarkersClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnErcCmpClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonCloseClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnResetMatrixClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Electrical Rules Checker"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 519,457 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_ERC_BASE(); + +}; + +#endif //__DIALOG_ERC_BASE_H__ diff --git a/eeschema/dialogs/dialog_lib_edit_draw_item.cpp b/eeschema/dialogs/dialog_lib_edit_draw_item.cpp new file mode 100644 index 00000000..d0bf3ef0 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_draw_item.cpp @@ -0,0 +1,131 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2006-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file dialog_lib_edit_draw_item.cpp + */ + +#include + + +DIALOG_LIB_EDIT_DRAW_ITEM::DIALOG_LIB_EDIT_DRAW_ITEM( wxWindow* parent, + const wxString& itemName ) : + DIALOG_LIB_EDIT_DRAW_ITEM_BASE( parent ) +{ + SetTitle( itemName + wxT( " " ) + GetTitle() ); + + // Required under wxGTK if we want to dismiss the dialog with the ESC key + SetFocus(); + m_sdbSizer1OK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::SetWidth( const wxString& width ) +{ + m_textWidth->SetValue( width ); +} + + +wxString DIALOG_LIB_EDIT_DRAW_ITEM::GetWidth( void ) +{ + return m_textWidth->GetValue(); +} + + +bool DIALOG_LIB_EDIT_DRAW_ITEM::GetApplyToAllConversions( void ) +{ + return m_checkApplyToAllConversions->IsChecked(); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::SetApplyToAllConversions( bool applyToAll ) +{ + m_checkApplyToAllConversions->SetValue( applyToAll ); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::EnableApplyToAllConversions( bool enable ) +{ + m_checkApplyToAllConversions->Enable( enable ); +} + + +bool DIALOG_LIB_EDIT_DRAW_ITEM::GetApplyToAllUnits( void ) +{ + return m_checkApplyToAllUnits->IsChecked(); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::SetApplyToAllUnits( bool applyToAll ) +{ + m_checkApplyToAllUnits->SetValue( applyToAll ); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::EnableApplyToAllUnits( bool enable ) +{ + m_checkApplyToAllUnits->Enable( enable ); +} + + +int DIALOG_LIB_EDIT_DRAW_ITEM::GetFillStyle( void ) +{ + if( m_radioFillNone->GetValue() ) + return 0; + if( m_radioFillForeground->GetValue() ) + return 1; + if( m_radioFillBackground->GetValue() ) + return 2; + + return 0; +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::SetFillStyle( int fillStyle ) +{ + if( fillStyle == 1 ) + m_radioFillForeground->SetValue( true ); + else if( fillStyle == 2 ) + m_radioFillBackground->SetValue( true ); + else + m_radioFillNone->SetValue( true ); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::EnableFillStyle( bool enable ) +{ + m_radioFillNone->Enable( enable ); + m_radioFillForeground->Enable( enable ); + m_radioFillBackground->Enable( enable ); +} + + +void DIALOG_LIB_EDIT_DRAW_ITEM::SetWidthUnits( const wxString& units ) +{ + m_staticWidthUnits->SetLabel( units ); +} diff --git a/eeschema/dialogs/dialog_lib_edit_draw_item.fbp b/eeschema/dialogs/dialog_lib_edit_draw_item.fbp new file mode 100644 index 00000000..323b7d37 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_draw_item.fbp @@ -0,0 +1,1205 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + table + dialog_lib_edit_draw_item_base + 1000 + none + 1 + dialog_lib_edit_draw_item + + . + + 1 + 1 + 1 + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIB_EDIT_DRAW_ITEM_BASE + + + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Drawing Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxHORIZONTAL + none + + 12 + wxALL|wxEXPAND + 1 + + + dlgBorderSizer + wxVERTICAL + none + + 3 + wxALIGN_LEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + General + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxALL|wxEXPAND + 0 + + + bSizer3 + wxHORIZONTAL + none + + 3 + wxEXPAND + 0 + + 0 + protected + 12 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Width: + + 0 + + + 0 + + 1 + m_staticWidth + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textWidth + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + + 0 + + + 0 + + 1 + m_staticWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + ID_M_STATICTEXTSHARING + Sharing + + 0 + + + 0 + + 1 + m_staticTextSharing + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxALL|wxEXPAND + 0 + + + bSizer4 + wxHORIZONTAL + none + + 3 + wxEXPAND + 0 + + 0 + protected + 12 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all &units in component + + 0 + + + 0 + + 1 + m_checkApplyToAllUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND + 0 + + + bSizer5 + wxHORIZONTAL + none + + 3 + wxEXPAND + 0 + + 0 + protected + 12 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all body &styles (DeMorgan) + + 0 + + + 0 + + 1 + m_checkApplyToAllConversions + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALL|wxEXPAND + 0 + + 0 + protected + 0 + + + + 3 + wxALIGN_LEFT|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Fill Style + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxALL|wxEXPAND + 1 + + + bSizer6 + wxHORIZONTAL + none + + 3 + wxEXPAND + 0 + + 0 + protected + 12 + + + + 0 + wxEXPAND + 0 + + + bSizer7 + wxVERTICAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Do &not fill + + 0 + + + 0 + + 1 + m_radioFillNone + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Fill &foreground + + 0 + + + 0 + + 1 + m_radioFillForeground + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Fill &background + + 0 + + + 0 + + 1 + m_radioFillBackground + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALL|wxEXPAND + 0 + + 0 + protected + 0 + + + + 0 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_edit_draw_item.h b/eeschema/dialogs/dialog_lib_edit_draw_item.h new file mode 100644 index 00000000..3680a1fb --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_draw_item.h @@ -0,0 +1,67 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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_lib_edit_draw_item__ +#define __dialog_lib_edit_draw_item__ + +/** + * @file + * Subclass of DIALOG_LIB_EDIT_DRAW_ITEM_BASE, which is generated by + * wxFormBuilder. + */ + +class LIB_DRAW_ITEM; + + +#include + + +/** + * Dialog to edit library component graphic items. + */ +class DIALOG_LIB_EDIT_DRAW_ITEM : public DIALOG_LIB_EDIT_DRAW_ITEM_BASE +{ +public: + /** Constructor */ + DIALOG_LIB_EDIT_DRAW_ITEM( wxWindow* parent, const wxString& itemName ); + + wxString GetWidth( void ); + void SetWidth( const wxString& width ); + + bool GetApplyToAllConversions( void ); + void SetApplyToAllConversions( bool applyToAll ); + void EnableApplyToAllConversions( bool enable = true ); + + bool GetApplyToAllUnits( void ); + void SetApplyToAllUnits( bool applyToAll ); + void EnableApplyToAllUnits( bool enable = true ); + + int GetFillStyle( void ); + void SetFillStyle( int fillStyle ); + void EnableFillStyle( bool enable = true ); + + void SetWidthUnits( const wxString& units ); +}; + +#endif // __dialog_lib_edit_draw_item__ diff --git a/eeschema/dialogs/dialog_lib_edit_draw_item_base.cpp b/eeschema/dialogs/dialog_lib_edit_draw_item_base.cpp new file mode 100644 index 00000000..021d584e --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_draw_item_base.cpp @@ -0,0 +1,140 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_lib_edit_draw_item_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIB_EDIT_DRAW_ITEM_BASE::DIALOG_LIB_EDIT_DRAW_ITEM_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* dlgBorderSizer; + dlgBorderSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("General"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + m_staticText1->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); + + dlgBorderSizer->Add( m_staticText1, 0, wxALIGN_LEFT, 3 ); + + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer3->Add( 12, 0, 0, wxEXPAND, 3 ); + + m_staticWidth = new wxStaticText( this, wxID_ANY, _("&Width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticWidth->Wrap( -1 ); + bSizer3->Add( m_staticWidth, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + + bSizer3->Add( 0, 0, 1, wxEXPAND, 3 ); + + m_textWidth = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer3->Add( m_textWidth, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticWidthUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticWidthUnits->Wrap( -1 ); + bSizer3->Add( m_staticWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + + dlgBorderSizer->Add( bSizer3, 0, wxALL|wxEXPAND, 0 ); + + m_staticTextSharing = new wxStaticText( this, ID_M_STATICTEXTSHARING, _("Sharing"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSharing->Wrap( -1 ); + m_staticTextSharing->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); + + dlgBorderSizer->Add( m_staticTextSharing, 0, wxTOP|wxBOTTOM, 5 ); + + wxBoxSizer* bSizer4; + bSizer4 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer4->Add( 12, 0, 0, wxEXPAND, 3 ); + + m_checkApplyToAllUnits = new wxCheckBox( this, wxID_ANY, _("Common to all &units in component"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer4->Add( m_checkApplyToAllUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + + dlgBorderSizer->Add( bSizer4, 0, wxALL|wxEXPAND, 0 ); + + wxBoxSizer* bSizer5; + bSizer5 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer5->Add( 12, 0, 0, wxEXPAND, 3 ); + + m_checkApplyToAllConversions = new wxCheckBox( this, wxID_ANY, _("Common to all body &styles (DeMorgan)"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer5->Add( m_checkApplyToAllConversions, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + + dlgBorderSizer->Add( bSizer5, 0, wxEXPAND, 3 ); + + + dlgBorderSizer->Add( 0, 0, 0, wxALL|wxEXPAND, 10 ); + + m_staticText4 = new wxStaticText( this, wxID_ANY, _("Fill Style"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + m_staticText4->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); + + dlgBorderSizer->Add( m_staticText4, 0, wxALIGN_LEFT|wxBOTTOM, 3 ); + + wxBoxSizer* bSizer6; + bSizer6 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer6->Add( 12, 0, 0, wxEXPAND, 3 ); + + wxBoxSizer* bSizer7; + bSizer7 = new wxBoxSizer( wxVERTICAL ); + + m_radioFillNone = new wxRadioButton( this, wxID_ANY, _("Do ¬ fill"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + m_radioFillNone->SetValue( true ); + bSizer7->Add( m_radioFillNone, 0, wxALL, 3 ); + + m_radioFillForeground = new wxRadioButton( this, wxID_ANY, _("Fill &foreground"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer7->Add( m_radioFillForeground, 0, wxALL, 3 ); + + m_radioFillBackground = new wxRadioButton( this, wxID_ANY, _("Fill &background"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer7->Add( m_radioFillBackground, 0, wxALL, 3 ); + + + bSizer6->Add( bSizer7, 0, wxEXPAND, 0 ); + + + dlgBorderSizer->Add( bSizer6, 1, wxALL|wxEXPAND, 0 ); + + + dlgBorderSizer->Add( 0, 0, 0, wxALL|wxEXPAND, 10 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + dlgBorderSizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 0 ); + + + mainSizer->Add( dlgBorderSizer, 1, wxALL|wxEXPAND, 12 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + mainSizer->Fit( this ); + + this->Centre( wxBOTH ); +} + +DIALOG_LIB_EDIT_DRAW_ITEM_BASE::~DIALOG_LIB_EDIT_DRAW_ITEM_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_lib_edit_draw_item_base.h b/eeschema/dialogs/dialog_lib_edit_draw_item_base.h new file mode 100644 index 00000000..553e7d95 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_draw_item_base.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version May 21 2016) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIB_EDIT_DRAW_ITEM_BASE_H__ +#define __DIALOG_LIB_EDIT_DRAW_ITEM_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIB_EDIT_DRAW_ITEM_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIB_EDIT_DRAW_ITEM_BASE : public DIALOG_SHIM +{ + private: + + protected: + enum + { + ID_M_STATICTEXTSHARING = 1000 + }; + + wxStaticText* m_staticText1; + wxStaticText* m_staticWidth; + wxTextCtrl* m_textWidth; + wxStaticText* m_staticWidthUnits; + wxStaticText* m_staticTextSharing; + wxCheckBox* m_checkApplyToAllUnits; + wxCheckBox* m_checkApplyToAllConversions; + wxStaticText* m_staticText4; + wxRadioButton* m_radioFillNone; + wxRadioButton* m_radioFillForeground; + wxRadioButton* m_radioFillBackground; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + public: + + DIALOG_LIB_EDIT_DRAW_ITEM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Drawing Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIB_EDIT_DRAW_ITEM_BASE(); + +}; + +#endif //__DIALOG_LIB_EDIT_DRAW_ITEM_BASE_H__ diff --git a/eeschema/dialogs/dialog_lib_edit_pin.cpp b/eeschema/dialogs/dialog_lib_edit_pin.cpp new file mode 100644 index 00000000..19ced990 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin.cpp @@ -0,0 +1,193 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 +#include +#include +#include + +#include +#include +#include + +#include + +DIALOG_LIB_EDIT_PIN::DIALOG_LIB_EDIT_PIN( EDA_DRAW_FRAME* parent, LIB_PIN* aPin ) : + DIALOG_LIB_EDIT_PIN_BASE( parent ) +{ + // Creates a dummy pin to show on a panel, inside this dialog: + m_dummyPin = new LIB_PIN( *aPin ); + + // m_dummyPin changes do not propagate to other pins of the current lib component, + // so set parent to null and clear flags + m_dummyPin->SetParent( NULL ); + m_dummyPin->ClearFlags(); + + m_panelShowPin->SetBackgroundColour( MakeColour( parent->GetDrawBgColor() ) ); + + // Set tab order + m_textPadName->MoveAfterInTabOrder(m_textPinName); + m_sdbSizerButtonsOK->SetDefault(); + + GetSizer()->SetSizeHints( this ); + + // On some windows manager (Unity, XFCE), this dialog is + // not always raised, depending on this dialog is run. + // Force it to be raised + Raise(); +} + + +DIALOG_LIB_EDIT_PIN::~DIALOG_LIB_EDIT_PIN() +{ + delete m_dummyPin; +} + +void DIALOG_LIB_EDIT_PIN::OnInitDialog( wxInitDialogEvent& event ) +{ + m_textPinName->SetFocus(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + +/* + * Draw (on m_panelShowPin) the pin currently edited + * accroding to current settings in dialog + */ +void DIALOG_LIB_EDIT_PIN::OnPaintShowPanel( wxPaintEvent& event ) +{ + wxPaintDC dc( m_panelShowPin ); + wxSize dc_size = dc.GetSize(); + dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 ); + + // Give a parent to m_dummyPin only from draw purpose. + // In fact m_dummyPin should not have a parent, but draw functions need a parent + // to know some options, about pin texts + LIB_EDIT_FRAME* libframe = (LIB_EDIT_FRAME*) GetParent(); + m_dummyPin->SetParent( libframe->GetCurPart() ); + + // Calculate a suitable scale to fit the available draw area + EDA_RECT bBox = m_dummyPin->GetBoundingBox(); + double xscale = (double) dc_size.x / bBox.GetWidth(); + double yscale = (double) dc_size.y / bBox.GetHeight(); + double scale = std::min( xscale, yscale ); + + // Give a 10% margin + scale *= 0.9; + dc.SetUserScale( scale, scale ); + + wxPoint offset = -bBox.Centre(); + + GRResetPenAndBrush( &dc ); + bool drawpinTexts = true; // this is a dummy param. We use its reference + // as non null value for m_dummyPin->Draw + m_dummyPin->Draw( NULL, &dc, offset, UNSPECIFIED_COLOR, GR_COPY, + &drawpinTexts, DefaultTransform ); + + m_dummyPin->SetParent(NULL); + + event.Skip(); +} + +void DIALOG_LIB_EDIT_PIN::OnCloseDialog( wxCloseEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + +void DIALOG_LIB_EDIT_PIN::OnCancelButtonClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + +void DIALOG_LIB_EDIT_PIN::OnOKButtonClick( wxCommandEvent& event ) +{ + EndModal( wxID_OK ); +} + +// Called when a pin properties changes +void DIALOG_LIB_EDIT_PIN::OnPropertiesChange( wxCommandEvent& event ) +{ + if( ! IsShown() ) // do nothing at init time + return; + + int pinNameSize = ValueFromString( g_UserUnit, GetPinNameTextSize() ); + int pinNumSize = ValueFromString( g_UserUnit, GetPadNameTextSize()); + int pinOrient = LIB_PIN::GetOrientationCode( GetOrientation() ); + int pinLength = ValueFromString( g_UserUnit, GetLength() ); + int pinShape = LIB_PIN::GetStyleCode( GetStyle() ); + int pinType = GetElectricalType(); + + m_dummyPin->SetName( GetPinName() ); + m_dummyPin->SetNameTextSize( pinNameSize ); + m_dummyPin->SetNumber( GetPadName() ); + m_dummyPin->SetNumberTextSize( pinNumSize ); + m_dummyPin->SetOrientation( pinOrient ); + m_dummyPin->SetLength( pinLength ); + m_dummyPin->SetShape( pinShape ); + m_dummyPin->SetVisible( GetVisible() ); + m_dummyPin->SetType( pinType ); + + m_panelShowPin->Refresh(); +} + + +void DIALOG_LIB_EDIT_PIN::SetOrientationList( const wxArrayString& list, + const BITMAP_DEF* aBitmaps ) +{ + for ( unsigned ii = 0; ii < list.GetCount(); ii++ ) + { + if( aBitmaps == NULL ) + m_choiceOrientation->Append( list[ii] ); + else + m_choiceOrientation->Insert( list[ii], KiBitmap( aBitmaps[ii] ), ii ); + } +} + + +void DIALOG_LIB_EDIT_PIN::SetElectricalTypeList( const wxArrayString& list, + const BITMAP_DEF* aBitmaps ) +{ + for ( unsigned ii = 0; ii < list.GetCount(); ii++ ) + { + if( aBitmaps == NULL ) + m_choiceElectricalType->Append( list[ii] ); + else + m_choiceElectricalType->Insert( list[ii], KiBitmap( aBitmaps[ii] ), ii ); + } +} + + +void DIALOG_LIB_EDIT_PIN::SetStyleList( const wxArrayString& list, const BITMAP_DEF* aBitmaps ) +{ + for ( unsigned ii = 0; ii < list.GetCount(); ii++ ) + { + if( aBitmaps == NULL ) + m_choiceStyle->Append( list[ii] ); + else + m_choiceStyle->Insert( list[ii], KiBitmap( aBitmaps[ii] ), ii ); + } +} diff --git a/eeschema/dialogs/dialog_lib_edit_pin.h b/eeschema/dialogs/dialog_lib_edit_pin.h new file mode 100644 index 00000000..52227e21 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin.h @@ -0,0 +1,146 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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_lib_edit_pin__ +#define __dialog_lib_edit_pin__ + +/** + * @file + * Subclass of DIALOG_LIB_EDIT_PIN_BASE, which is generated by wxFormBuilder. + */ + +#include + +#include + +/** Implementing DIALOG_LIB_EDIT_PIN_BASE */ +class DIALOG_LIB_EDIT_PIN : public DIALOG_LIB_EDIT_PIN_BASE +{ + LIB_PIN * m_dummyPin; // a working copy used to show changes + +public: + /** Constructor */ + DIALOG_LIB_EDIT_PIN( EDA_DRAW_FRAME* parent, LIB_PIN* aPin ); + ~DIALOG_LIB_EDIT_PIN(); + + void OnInitDialog( wxInitDialogEvent& event); + + void OnCloseDialog( wxCloseEvent& event ); + void OnCancelButtonClick( wxCommandEvent& event ); + void OnOKButtonClick( wxCommandEvent& event ); + void OnPaintShowPanel( wxPaintEvent& event ); + void OnPropertiesChange( wxCommandEvent& event ); + + void SetOrientationList( const wxArrayString& list, const BITMAP_DEF* aBitmaps ); + void SetOrientation( int orientation ) + { + m_choiceOrientation->SetSelection( orientation ); + } + int GetOrientation( void ) { return m_choiceOrientation->GetSelection(); } + + void SetElectricalTypeList( const wxArrayString& list, const BITMAP_DEF* aBitmaps ); + void SetElectricalType( int type ) + { + m_choiceElectricalType->SetSelection( type ); + } + int GetElectricalType( void ) + { + return m_choiceElectricalType->GetSelection(); + } + + void SetStyleList( const wxArrayString& list, const BITMAP_DEF* aBitmaps ); + void SetStyle( int style ) { m_choiceStyle->SetSelection( style ); } + int GetStyle( void ) { return m_choiceStyle->GetSelection(); } + + void SetPinName( const wxString& name ) { m_textPinName->SetValue( name ); } + wxString GetPinName( void ) { return m_textPinName->GetValue(); } + + void SetPinNameTextSize( const wxString& size ) + { + m_textPinNameTextSize->SetValue( size ); + } + wxString GetPinNameTextSize( void ) + { + return m_textPinNameTextSize->GetValue(); + } + + void SetPinNameTextSizeUnits( const wxString& units ) + { + m_staticNameTextSizeUnits->SetLabel( units ); + } + + void SetPadName( const wxString& number ) + { + m_textPadName->SetValue( number ); + } + wxString GetPadName( void ) { return m_textPadName->GetValue(); } + + void SetPadNameTextSize( const wxString& size ) + { + m_textPadNameTextSize->SetValue( size ); + } + wxString GetPadNameTextSize( void ) + { + return m_textPadNameTextSize->GetValue(); + } + + void SetPadNameTextSizeUnits( const wxString& units ) + { + m_staticNumberTextSizeUnits->SetLabel( units ); + } + + void SetLength( const wxString& length ) + { + m_textLength->SetValue( length ); + } + wxString GetLength( void ) { return m_textLength->GetValue(); } + + void SetLengthUnits( const wxString& units ) + { + m_staticLengthUnits->SetLabel( units ); + } + + void SetAddToAllParts( bool apply ) + { + m_checkApplyToAllParts->SetValue( apply ); + } + bool GetAddToAllParts( void ) + { + return m_checkApplyToAllParts->GetValue(); + } + + void SetAddToAllBodyStyles( bool apply ) + { + m_checkApplyToAllConversions->SetValue( apply ); + } + bool GetAddToAllBodyStyles( void ) + { + return m_checkApplyToAllConversions->GetValue(); + } + + void SetVisible( bool visible ) { m_checkShow->SetValue( visible ); } + bool GetVisible( void ) { return m_checkShow->GetValue(); } +}; + +#endif // __dialog_lib_edit_pin__ diff --git a/eeschema/dialogs/dialog_lib_edit_pin_base.cpp b/eeschema/dialogs/dialog_lib_edit_pin_base.cpp new file mode 100644 index 00000000..39aa7c51 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_base.cpp @@ -0,0 +1,224 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "wx/bmpcbox.h" + +#include "dialog_lib_edit_pin_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIB_EDIT_PIN_BASE::DIALOG_LIB_EDIT_PIN_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bUpperSizer; + bUpperSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bLeftSizer; + bLeftSizer = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizerPins; + fgSizerPins = new wxFlexGridSizer( 5, 2, 0, 0 ); + fgSizerPins->AddGrowableCol( 1 ); + fgSizerPins->SetFlexibleDirection( wxBOTH ); + fgSizerPins->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_ALL ); + + m_staticTextPinName = new wxStaticText( this, wxID_ANY, _("Pin &name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPinName->Wrap( -1 ); + fgSizerPins->Add( m_staticTextPinName, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textPinName = new wxTextCtrl( this, ID_M_TEXTPINNAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textPinName->SetMaxLength( 0 ); + fgSizerPins->Add( m_textPinName, 0, wxEXPAND|wxTOP|wxBOTTOM, 3 ); + + m_staticTextPadName = new wxStaticText( this, ID_M_STATICTEXTPADNAME, _("Pin n&umber:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPadName->Wrap( -1 ); + m_staticTextPadName->SetToolTip( _("Pin number: 1 to 4 ASCII letters and/or digits") ); + + fgSizerPins->Add( m_staticTextPadName, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textPadName = new wxTextCtrl( this, ID_M_TEXTPADNAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textPadName->SetMaxLength( 0 ); + fgSizerPins->Add( m_textPadName, 0, wxEXPAND|wxTOP|wxBOTTOM, 3 ); + + m_staticTextOrient = new wxStaticText( this, wxID_ANY, _("&Orientation:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextOrient->Wrap( -1 ); + fgSizerPins->Add( m_staticTextOrient, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_choiceOrientation = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY ); + fgSizerPins->Add( m_choiceOrientation, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + m_staticTextEType = new wxStaticText( this, wxID_ANY, _("&Electrical type:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextEType->Wrap( -1 ); + m_staticTextEType->SetToolTip( _("Used by the ERC.") ); + + fgSizerPins->Add( m_staticTextEType, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_choiceElectricalType = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY ); + fgSizerPins->Add( m_choiceElectricalType, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + m_staticTextGstyle = new wxStaticText( this, wxID_ANY, _("Graphic &Style:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextGstyle->Wrap( -1 ); + fgSizerPins->Add( m_staticTextGstyle, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_choiceStyle = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY ); + fgSizerPins->Add( m_choiceStyle, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + + bLeftSizer->Add( fgSizerPins, 0, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* boarderSizer; + boarderSizer = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* sbSizerPinSharing; + sbSizerPinSharing = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Sharing") ), wxVERTICAL ); + + m_checkApplyToAllParts = new wxCheckBox( this, wxID_ANY, _("Common to all &units in component"), wxDefaultPosition, wxDefaultSize, 0 ); + sbSizerPinSharing->Add( m_checkApplyToAllParts, 0, wxALL, 3 ); + + m_checkApplyToAllConversions = new wxCheckBox( this, wxID_ANY, _("Common to all body &styles (DeMorgan)"), wxDefaultPosition, wxDefaultSize, 0 ); + sbSizerPinSharing->Add( m_checkApplyToAllConversions, 0, wxALL, 3 ); + + + boarderSizer->Add( sbSizerPinSharing, 0, wxEXPAND|wxALL, 5 ); + + wxStaticBoxSizer* sbSizerSchematicProperties; + sbSizerSchematicProperties = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Schematic Properties") ), wxVERTICAL ); + + m_checkShow = new wxCheckBox( this, wxID_ANY, _("&Visible"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkShow->SetValue(true); + sbSizerSchematicProperties->Add( m_checkShow, 0, wxALL, 3 ); + + + boarderSizer->Add( sbSizerSchematicProperties, 0, wxEXPAND|wxALL, 5 ); + + + bLeftSizer->Add( boarderSizer, 0, wxEXPAND|wxTOP|wxBOTTOM, 12 ); + + + bUpperSizer->Add( bLeftSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bRightSizer; + bRightSizer = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizerTextsSizes; + fgSizerTextsSizes = new wxFlexGridSizer( 3, 3, 0, 0 ); + fgSizerTextsSizes->AddGrowableCol( 1 ); + fgSizerTextsSizes->SetFlexibleDirection( wxBOTH ); + fgSizerTextsSizes->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_ALL ); + + m_staticTextNameSize = new wxStaticText( this, ID_M_STATICTEXTNAMESIZE, _("N&ame text size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextNameSize->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticTextNameSize, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textPinNameTextSize = new wxTextCtrl( this, ID_M_TEXTPINNAMETEXTSIZE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textPinNameTextSize->SetMaxLength( 0 ); + fgSizerTextsSizes->Add( m_textPinNameTextSize, 1, wxEXPAND|wxTOP|wxBOTTOM, 3 ); + + m_staticNameTextSizeUnits = new wxStaticText( this, ID_M_STATICNAMETEXTSIZEUNITS, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticNameTextSizeUnits->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticNameTextSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticTextPadNameSize = new wxStaticText( this, ID_M_STATICTEXTPADNAMESIZE, _("Number te&xt size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPadNameSize->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticTextPadNameSize, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textPadNameTextSize = new wxTextCtrl( this, ID_M_TEXTPADNAMETEXTSIZE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textPadNameTextSize->SetMaxLength( 0 ); + fgSizerTextsSizes->Add( m_textPadNameTextSize, 0, wxTOP|wxBOTTOM|wxEXPAND, 3 ); + + m_staticNumberTextSizeUnits = new wxStaticText( this, ID_M_STATICNUMBERTEXTSIZEUNITS, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticNumberTextSizeUnits->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticNumberTextSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticTextPinLen = new wxStaticText( this, ID_M_STATICTEXTPINLEN, _("&Length:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextPinLen->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticTextPinLen, 0, wxALL, 5 ); + + m_textLength = new wxTextCtrl( this, ID_M_TEXTLENGTH, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textLength->SetMaxLength( 0 ); + fgSizerTextsSizes->Add( m_textLength, 0, wxTOP|wxBOTTOM|wxEXPAND, 5 ); + + m_staticLengthUnits = new wxStaticText( this, ID_M_STATICLENGTHUNITS, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticLengthUnits->Wrap( -1 ); + fgSizerTextsSizes->Add( m_staticLengthUnits, 0, wxALL, 5 ); + + + bRightSizer->Add( fgSizerTextsSizes, 0, wxALL|wxEXPAND, 5 ); + + m_panelShowPin = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER|wxTAB_TRAVERSAL ); + m_panelShowPin->SetMinSize( wxSize( 150,150 ) ); + + bRightSizer->Add( m_panelShowPin, 1, wxEXPAND | wxALL, 5 ); + + + bUpperSizer->Add( bRightSizer, 1, wxEXPAND|wxRIGHT, 5 ); + + + mainSizer->Add( bUpperSizer, 1, wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + mainSizer->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_sdbSizerButtons = new wxStdDialogButtonSizer(); + m_sdbSizerButtonsOK = new wxButton( this, wxID_OK ); + m_sdbSizerButtons->AddButton( m_sdbSizerButtonsOK ); + m_sdbSizerButtonsCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizerButtons->AddButton( m_sdbSizerButtonsCancel ); + m_sdbSizerButtons->Realize(); + + mainSizer->Add( m_sdbSizerButtons, 0, wxALL|wxALIGN_RIGHT, 5 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnCloseDialog ) ); + this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnInitDialog ) ); + m_textPinName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPadName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceOrientation->Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceElectricalType->Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceStyle->Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkApplyToAllParts->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkApplyToAllConversions->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkShow->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPinNameTextSize->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPadNameTextSize->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textLength->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_panelShowPin->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPaintShowPanel ), NULL, this ); + m_sdbSizerButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnCancelButtonClick ), NULL, this ); + m_sdbSizerButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnOKButtonClick ), NULL, this ); +} + +DIALOG_LIB_EDIT_PIN_BASE::~DIALOG_LIB_EDIT_PIN_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnCloseDialog ) ); + this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnInitDialog ) ); + m_textPinName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPadName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceOrientation->Disconnect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceElectricalType->Disconnect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_choiceStyle->Disconnect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkApplyToAllParts->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkApplyToAllConversions->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_checkShow->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPinNameTextSize->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textPadNameTextSize->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_textLength->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPropertiesChange ), NULL, this ); + m_panelShowPin->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnPaintShowPanel ), NULL, this ); + m_sdbSizerButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnCancelButtonClick ), NULL, this ); + m_sdbSizerButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_BASE::OnOKButtonClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_lib_edit_pin_base.fbp b/eeschema/dialogs/dialog_lib_edit_pin_base.fbp new file mode 100644 index 00000000..a4523b01 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_base.fbp @@ -0,0 +1,2299 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_lib_edit_pin_base + 1000 + none + 1 + dialog_lib_edit_pin + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIB_EDIT_PIN_BASE + + 515,370 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Pin Properties + + + + + + + + + + + + + + OnCloseDialog + + + + + + OnInitDialog + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bUpperSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bLeftSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizerPins + wxFLEX_GROWMODE_ALL + none + 5 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pin &name: + + 0 + + + 0 + + 1 + m_staticTextPinName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_TEXTPINNAME + + 0 + + 0 + + 0 + + 1 + m_textPinName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnPropertiesChange + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICTEXTPADNAME + Pin n&umber: + + 0 + + + 0 + + 1 + m_staticTextPadName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Pin number: 1 to 4 ASCII letters and/or digits + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_TEXTPADNAME + + 0 + + 0 + + 0 + + 1 + m_textPadName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnPropertiesChange + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Orientation: + + 0 + + + 0 + + 1 + m_staticTextOrient + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceOrientation + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + wxBitmapComboBox; wx/bmpcbox.h + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Electrical type: + + 0 + + + 0 + + 1 + m_staticTextEType + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Used by the ERC. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceElectricalType + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + wxBitmapComboBox; wx/bmpcbox.h + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Graphic &Style: + + 0 + + + 0 + + 1 + m_staticTextGstyle + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceStyle + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + wxBitmapComboBox; wx/bmpcbox.h + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + + boarderSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + Sharing + + sbSizerPinSharing + wxVERTICAL + none + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all &units in component + + 0 + + + 0 + + 1 + m_checkApplyToAllParts + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all body &styles (DeMorgan) + + 0 + + + 0 + + 1 + m_checkApplyToAllConversions + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + Schematic Properties + + sbSizerSchematicProperties + wxVERTICAL + none + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Visible + + 0 + + + 0 + + 1 + m_checkShow + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnPropertiesChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 1 + + + bRightSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 3 + wxBOTH + 1 + + 0 + + fgSizerTextsSizes + wxFLEX_GROWMODE_ALL + none + 3 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICTEXTNAMESIZE + N&ame text size: + + 0 + + + 0 + + 1 + m_staticTextNameSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxBOTTOM + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_TEXTPINNAMETEXTSIZE + + 0 + + 0 + + 0 + + 1 + m_textPinNameTextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnPropertiesChange + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICNAMETEXTSIZEUNITS + units + + 0 + + + 0 + -1,-1 + 1 + m_staticNameTextSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICTEXTPADNAMESIZE + Number te&xt size: + + 0 + + + 0 + + 1 + m_staticTextPadNameSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxTOP|wxBOTTOM|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_TEXTPADNAMETEXTSIZE + + 0 + + 0 + + 0 + + 1 + m_textPadNameTextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnPropertiesChange + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICNUMBERTEXTSIZEUNITS + units + + 0 + + + 0 + + 1 + m_staticNumberTextSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICTEXTPINLEN + &Length: + + 0 + + + 0 + + 1 + m_staticTextPinLen + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxBOTTOM|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_TEXTLENGTH + + 0 + + 0 + + 0 + + 1 + m_textLength + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnPropertiesChange + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_M_STATICLENGTHUNITS + units + + 0 + + + 0 + + 1 + m_staticLengthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 150,150 + 1 + m_panelShowPin + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER|wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + OnPaintShowPanel + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_RIGHT + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizerButtons + protected + + OnCancelButtonClick + + + + OnOKButtonClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_edit_pin_base.h b/eeschema/dialogs/dialog_lib_edit_pin_base.h new file mode 100644 index 00000000..548601f7 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_base.h @@ -0,0 +1,104 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIB_EDIT_PIN_BASE_H__ +#define __DIALOG_LIB_EDIT_PIN_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; +class wxBitmapComboBox; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIB_EDIT_PIN_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIB_EDIT_PIN_BASE : public DIALOG_SHIM +{ + private: + + protected: + enum + { + ID_M_TEXTPINNAME = 1000, + ID_M_STATICTEXTPADNAME, + ID_M_TEXTPADNAME, + ID_M_STATICTEXTNAMESIZE, + ID_M_TEXTPINNAMETEXTSIZE, + ID_M_STATICNAMETEXTSIZEUNITS, + ID_M_STATICTEXTPADNAMESIZE, + ID_M_TEXTPADNAMETEXTSIZE, + ID_M_STATICNUMBERTEXTSIZEUNITS, + ID_M_STATICTEXTPINLEN, + ID_M_TEXTLENGTH, + ID_M_STATICLENGTHUNITS + }; + + wxStaticText* m_staticTextPinName; + wxTextCtrl* m_textPinName; + wxStaticText* m_staticTextPadName; + wxTextCtrl* m_textPadName; + wxStaticText* m_staticTextOrient; + wxBitmapComboBox* m_choiceOrientation; + wxStaticText* m_staticTextEType; + wxBitmapComboBox* m_choiceElectricalType; + wxStaticText* m_staticTextGstyle; + wxBitmapComboBox* m_choiceStyle; + wxCheckBox* m_checkApplyToAllParts; + wxCheckBox* m_checkApplyToAllConversions; + wxCheckBox* m_checkShow; + wxStaticText* m_staticTextNameSize; + wxTextCtrl* m_textPinNameTextSize; + wxStaticText* m_staticNameTextSizeUnits; + wxStaticText* m_staticTextPadNameSize; + wxTextCtrl* m_textPadNameTextSize; + wxStaticText* m_staticNumberTextSizeUnits; + wxStaticText* m_staticTextPinLen; + wxTextCtrl* m_textLength; + wxStaticText* m_staticLengthUnits; + wxPanel* m_panelShowPin; + wxStaticLine* m_staticline1; + wxStdDialogButtonSizer* m_sdbSizerButtons; + wxButton* m_sdbSizerButtonsOK; + wxButton* m_sdbSizerButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); } + virtual void OnInitDialog( wxInitDialogEvent& event ) { event.Skip(); } + virtual void OnPropertiesChange( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPaintShowPanel( wxPaintEvent& event ) { event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_LIB_EDIT_PIN_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pin Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 515,370 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIB_EDIT_PIN_BASE(); + +}; + +#endif //__DIALOG_LIB_EDIT_PIN_BASE_H__ diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table.cpp b/eeschema/dialogs/dialog_lib_edit_pin_table.cpp new file mode 100644 index 00000000..dc39b53d --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_table.cpp @@ -0,0 +1,584 @@ +#include "dialog_lib_edit_pin_table.h" + +#include "lib_pin.h" + +#include +#include + +/* Avoid wxWidgets bug #16906 -- http://trac.wxwidgets.org/ticket/16906 + * + * If multiple elements live in the root of a wxDataViewCtrl, using + * ItemsAdded() can run into an assertion failure. To avoid this, we avoid + * notifying the widget of changes, but rather reinitialize it. + * + * When a fix for this exists in wxWidgets, this is the place to turn it + * off. + */ +#define REASSOCIATE_HACK + +class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel : + public wxDataViewModel +{ +public: + DataViewModel( LIB_PART& aPart ); + + // wxDataViewModel + virtual unsigned int GetColumnCount() const; + virtual wxString GetColumnType( unsigned int col ) const; + virtual void GetValue( wxVariant&, const wxDataViewItem&, unsigned int ) const; + virtual bool SetValue( const wxVariant&, const wxDataViewItem&, unsigned int ); + virtual wxDataViewItem GetParent( const wxDataViewItem& ) const; + virtual bool IsContainer( const wxDataViewItem& ) const; + virtual bool HasContainerColumns( const wxDataViewItem& ) const; + virtual unsigned int GetChildren( const wxDataViewItem&, wxDataViewItemArray& ) const; + + virtual int Compare( const wxDataViewItem& lhs, + const wxDataViewItem& rhs, + unsigned int col, + bool ascending ) const; + + void SetGroupingColumn( int aCol ); + void CalculateGrouping(); + void Refresh(); + +#ifdef REASSOCIATE_HACK + void SetWidget( wxDataViewCtrl* aWidget ) { m_Widget = aWidget; } +#endif + + enum + { + NONE = -1, + PIN_NUMBER = 0, + PIN_NAME = 1, + PIN_TYPE = 2, + PIN_POSITION = 3 + }; + +private: + LIB_PART& m_Part; + LIB_PINS m_Backing; + int m_GroupingColumn; + int m_UnitCount; + + class Item; + class Group; + class Pin; + + mutable std::list m_Pins; + mutable std::map m_Groups; + +#ifdef REASSOCIATE_HACK + wxDataViewCtrl* m_Widget; +#endif +}; + +class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Item +{ +public: + virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const = 0; + virtual wxDataViewItem GetParent() const = 0; + virtual bool IsContainer() const = 0; + virtual unsigned int GetChildren( wxDataViewItemArray& ) const = 0; +}; + +class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group : + public Item +{ +public: + Group( unsigned int aGroupingColumn ) : m_GroupingColumn( aGroupingColumn ) {} + + virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const; + + virtual wxDataViewItem GetParent() const { return wxDataViewItem(); } + virtual bool IsContainer() const { return true; } + virtual unsigned int GetChildren( wxDataViewItemArray& aItems ) const + { + /// @todo C++11 + for( std::list::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i ) + aItems.push_back( wxDataViewItem( *i ) ); + + return aItems.size(); + } + + unsigned int GetCount() const { return m_Members.size(); } + void Add( Pin* aPin ); + +private: + std::list m_Members; + unsigned int m_GroupingColumn; +}; + +class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Pin : + public Item +{ +public: + Pin( DataViewModel& aModel, + LIB_PIN* aBacking ) : m_Model( aModel ), m_Backing( aBacking ), m_Group( 0 ) {} + + virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const; + + virtual wxDataViewItem GetParent() const { return wxDataViewItem( m_Group ); } + virtual bool IsContainer() const { return false; } + virtual unsigned int GetChildren( wxDataViewItemArray& ) const { return 0; } + + void SetGroup( Group* aGroup ) { m_Group = aGroup; } + +private: + DataViewModel& m_Model; + LIB_PIN* m_Backing; + Group* m_Group; +}; + +DIALOG_LIB_EDIT_PIN_TABLE::DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, + LIB_PART& aPart ) : + DIALOG_LIB_EDIT_PIN_TABLE_BASE( parent ), + m_Model( new DataViewModel( aPart ) ) +{ +#ifdef REASSOCIATE_HACK + m_Model->SetWidget( m_Pins ); +#endif + m_Pins->AssociateModel( m_Model.get() ); + + /// @todo wxFormBuilder bug #61 -- move to base once supported + wxDataViewTextRenderer* rend0 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); + wxDataViewColumn* col0 = new wxDataViewColumn( _( "Number" ), + rend0, + DataViewModel::PIN_NUMBER, + 100, + wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), + wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); + wxDataViewTextRenderer* rend1 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); + wxDataViewColumn* col1 = new wxDataViewColumn( _( "Name" ), + rend1, + DataViewModel::PIN_NAME, + 100, + wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), + wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); + wxDataViewTextRenderer* rend2 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); + wxDataViewColumn* col2 = new wxDataViewColumn( _( "Type" ), + rend2, + DataViewModel::PIN_TYPE, + 100, + wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), + wxDATAVIEW_COL_RESIZABLE ); + wxDataViewTextRenderer* rend3 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); + wxDataViewColumn* col3 = new wxDataViewColumn( _( "Position" ), + rend3, + DataViewModel::PIN_POSITION, + 100, + wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), + wxDATAVIEW_COL_RESIZABLE ); + m_Pins->AppendColumn( col0 ); + m_Pins->SetExpanderColumn( col0 ); + m_Pins->AppendColumn( col1 ); + m_Pins->AppendColumn( col2 ); + m_Pins->AppendColumn( col3 ); + + GetSizer()->SetSizeHints(this); + Centre(); +} + + +DIALOG_LIB_EDIT_PIN_TABLE::~DIALOG_LIB_EDIT_PIN_TABLE() +{ +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::OnColumnHeaderRightClicked( wxDataViewEvent& event ) +{ + m_Model->SetGroupingColumn( event.GetDataViewColumn()->GetModelColumn() ); + event.Skip(); +} + + +DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::DataViewModel( LIB_PART& aPart ) : + m_Part( aPart ), + m_GroupingColumn( 1 ), + m_UnitCount( m_Part.GetUnitCount() ) +{ +#ifdef REASSOCIATE_HACK + m_Widget = NULL; +#endif + aPart.GetPins( m_Backing ); + /// @todo C++11 + for( LIB_PINS::const_iterator i = m_Backing.begin(); i != m_Backing.end(); ++i ) + m_Pins.push_back( Pin( *this, *i ) ); + + CalculateGrouping(); +} + + +unsigned int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetColumnCount() const +{ + return 4; +} + + +wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetColumnType( unsigned int aCol ) const +{ + return wxT( "string" ); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetValue( wxVariant& aVal, + const wxDataViewItem& aItem, + unsigned int aCol ) const +{ + assert( aItem.IsOk() ); + + reinterpret_cast( aItem.GetID() )->GetValue( aVal, aCol ); +} + + +bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::SetValue( const wxVariant&, + const wxDataViewItem&, + unsigned int ) +{ + return false; +} + + +wxDataViewItem DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetParent( const wxDataViewItem& aItem ) +const +{ + assert( aItem.IsOk() ); + + return reinterpret_cast( aItem.GetID() )->GetParent(); +} + + +bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::IsContainer( const wxDataViewItem& aItem ) const +{ + if( aItem.IsOk() ) + return reinterpret_cast( aItem.GetID() )->IsContainer(); + else + return true; +} + + +bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::HasContainerColumns( const wxDataViewItem& ) const +{ + return true; +} + + +unsigned int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetChildren( const wxDataViewItem& aItem, + wxDataViewItemArray& aItems ) const +{ + if( !aItem.IsOk() ) + { + for( std::map::iterator i = m_Groups.begin(); i != m_Groups.end(); ++i ) + if( i->second.GetCount() > 1 ) + aItems.push_back( wxDataViewItem( &i->second ) ); + + for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) + if( !i->GetParent().IsOk() ) + aItems.push_back( wxDataViewItem( &*i ) ); + + return aItems.size(); + } + else + return reinterpret_cast( aItem.GetID() )->GetChildren( aItems ); +} + + +namespace { +wxString GetNextComponent( const wxString& str, wxString::size_type& cursor ) +{ + if( str.size() <= cursor ) + return wxEmptyString; + + wxString::size_type begin = cursor; + + wxUniChar c = str[cursor]; + + if( isdigit( c ) || c == '+' || c == '-' ) + { + // number, possibly with sign + while( ++cursor < str.size() ) + { + c = str[cursor]; + + if( isdigit( c ) || c == 'v' || c == 'V' ) + continue; + else + break; + } + } + else + { + while( ++cursor < str.size() ) + { + c = str[cursor]; + + if( isdigit( c ) ) + break; + else + continue; + } + } + + return str.substr( begin, cursor - begin ); +} + + +int ComparePinNames( const wxString& lhs, const wxString& rhs ) +{ + wxString::size_type cursor1 = 0; + wxString::size_type cursor2 = 0; + + wxString comp1, comp2; + + for( ; ; ) + { + comp1 = GetNextComponent( lhs, cursor1 ); + comp2 = GetNextComponent( rhs, cursor2 ); + + if( comp1.empty() && comp2.empty() ) + return 0; + + if( comp1.empty() ) + return -1; + + if( comp2.empty() ) + return 1; + + wxUniChar c1 = comp1[0]; + wxUniChar c2 = comp2[0]; + + if( isdigit( c1 ) || c1 == '-' || c1 == '+' ) + { + if( isdigit( c2 ) || c2 == '-' || c2 == '+' ) + { + // numeric comparison + wxString::size_type v1 = comp1.find_first_of( "vV" ); + + if( v1 != wxString::npos ) + comp1[v1] = '.'; + + wxString::size_type v2 = comp2.find_first_of( "vV" ); + + if( v2 != wxString::npos ) + comp2[v2] = '.'; + + double val1, val2; + + comp1.ToDouble( &val1 ); + comp2.ToDouble( &val2 ); + + if( val1 < val2 ) + return -1; + + if( val1 > val2 ) + return 1; + } + else + return -1; + } + else + { + if( isdigit( c2 ) || c2 == '-' || c2 == '+' ) + return 1; + + int res = comp1.Cmp( comp2 ); + + if( res != 0 ) + return res; + } + } +} + + +class CompareLess +{ +public: + bool operator()( const wxString& lhs, const wxString& rhs ) + { + return ComparePinNames( lhs, rhs ) == -1; + } +}; +} + +int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Compare( const wxDataViewItem& aItem1, + const wxDataViewItem& aItem2, + unsigned int aCol, + bool aAscending ) const +{ + wxVariant var1; + + GetValue( var1, aItem1, aCol ); + wxString str1 = var1.GetString(); + + wxVariant var2; + GetValue( var2, aItem2, aCol ); + wxString str2 = var2.GetString(); + + int res = ComparePinNames( str1, str2 ); + + if( res == 0 ) + res = ( aItem1.GetID() < aItem2.GetID() ) ? -1 : 1; + + return res * ( aAscending ? 1 : -1 ); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::SetGroupingColumn( int aCol ) +{ + if( m_GroupingColumn == aCol ) + return; + + m_GroupingColumn = aCol; + + Cleared(); + CalculateGrouping(); + Refresh(); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::CalculateGrouping() +{ + m_Groups.clear(); + + if( m_GroupingColumn != -1 ) + { + wxVariant value; + + for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) + { + i->GetValue( value, m_GroupingColumn ); + wxString str = value.GetString(); + std::map::iterator j = m_Groups.find( str ); + + if( j == m_Groups.end() ) + j = m_Groups.insert( std::make_pair( str, m_GroupingColumn ) ).first; + + j->second.Add( &*i ); + } + } + else + { + for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) + i->SetGroup( 0 ); + } +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Refresh() +{ +#ifdef REASSOCIATE_HACK + m_Widget->AssociateModel( this ); +#else + std::queue todo; + todo.push( wxDataViewItem() ); + + while( !todo.empty() ) + { + wxDataViewItem current = todo.front(); + wxDataViewItemArray items; + + GetChildren( current, items ); + ItemsAdded( current, items ); + + for( wxDataViewItemArray::const_iterator i = items.begin(); i != items.end(); ++i ) + { + if( IsContainer( *i ) ) + todo.push( *i ); + } + + todo.pop(); + } + +#endif +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group::GetValue( wxVariant& aValue, + unsigned int aCol ) const +{ + if( aCol == m_GroupingColumn ) + { + // shortcut + m_Members.front()->GetValue( aValue, aCol ); + } + else + { + std::set values; + + for( std::list::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i ) + { + wxVariant value; + (*i)->GetValue( value, aCol ); + values.insert( value.GetString() ); + } + + aValue = boost::algorithm::join( values, "," ); + } +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group::Add( Pin* aPin ) +{ + switch( GetCount() ) + { + case 0: + aPin->SetGroup( 0 ); + break; + + case 1: + m_Members.front()->SetGroup( this ); + // fall through + + default: + aPin->SetGroup( this ); + } + + m_Members.push_back( aPin ); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Pin::GetValue( wxVariant& aValue, + unsigned int aCol ) const +{ + switch( aCol ) + { + case PIN_NUMBER: + aValue = m_Backing->GetNumberString(); + break; + + case PIN_NAME: + { + if( m_Model.m_UnitCount > 1 ) + { + wxString name; + int unit = m_Backing->GetPartNumber(); + + if( unit ) + name << unit; + else + name << "com"; + + name << ':'; + name << m_Backing->GetName(); + aValue = name; + } + else + { + aValue = m_Backing->GetName(); + } + } + break; + + case PIN_TYPE: + aValue = m_Backing->GetElectricalTypeName(); + break; + + case PIN_POSITION: + { + wxPoint position = m_Backing->GetPosition(); + wxString value; + value << "(" << position.x << "," << position.y << ")"; + aValue = value; + } + break; + } +} diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table.h b/eeschema/dialogs/dialog_lib_edit_pin_table.h new file mode 100644 index 00000000..345a77c3 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_table.h @@ -0,0 +1,18 @@ +#include "dialog_lib_edit_pin_table_base.h" + +#include "class_library.h" + +class DIALOG_LIB_EDIT_PIN_TABLE : + public DIALOG_LIB_EDIT_PIN_TABLE_BASE +{ +public: + DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, LIB_PART& aPart ); + ~DIALOG_LIB_EDIT_PIN_TABLE(); + + virtual void OnColumnHeaderRightClicked( wxDataViewEvent& aEvent ); + +private: + class DataViewModel; + + wxObjectDataPtr m_Model; +}; diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp b/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp new file mode 100644 index 00000000..3e82df54 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp @@ -0,0 +1,46 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_lib_edit_pin_table_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIB_EDIT_PIN_TABLE_BASE::DIALOG_LIB_EDIT_PIN_TABLE_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* top_sizer; + top_sizer = new wxBoxSizer( wxVERTICAL ); + + m_Pins = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxDV_HORIZ_RULES|wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES ); + m_Pins->SetMinSize( wxSize( 400,400 ) ); + + top_sizer->Add( m_Pins, 1, wxALL|wxEXPAND, 5 ); + + m_Buttons = new wxStdDialogButtonSizer(); + m_ButtonsOK = new wxButton( this, wxID_OK ); + m_Buttons->AddButton( m_ButtonsOK ); + m_Buttons->Realize(); + + top_sizer->Add( m_Buttons, 0, wxEXPAND|wxALL, 5 ); + + + this->SetSizer( top_sizer ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxID_ANY, wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, wxDataViewEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnColumnHeaderRightClicked ) ); +} + +DIALOG_LIB_EDIT_PIN_TABLE_BASE::~DIALOG_LIB_EDIT_PIN_TABLE_BASE() +{ + // Disconnect Events + this->Disconnect( wxID_ANY, wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, wxDataViewEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnColumnHeaderRightClicked ) ); + +} diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp b/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp new file mode 100644 index 00000000..b618c106 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp @@ -0,0 +1,193 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_lib_edit_pin_table_base + 1000 + none + 1 + dialog_lib_edit_pin_table + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + decl_pure_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIB_EDIT_PIN_TABLE_BASE + + 431,304 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Pin Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top_sizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + 1 + + + 0 + wxID_ANY + + 400,400 + m_Pins + protected + + -1,-1 + wxDV_HORIZ_RULES|wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES + + + + + + + + OnColumnHeaderRightClicked + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + + m_Buttons + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.h b/eeschema/dialogs/dialog_lib_edit_pin_table_base.h new file mode 100644 index 00000000..5763e403 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.h @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIB_EDIT_PIN_TABLE_BASE_H__ +#define __DIALOG_LIB_EDIT_PIN_TABLE_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIB_EDIT_PIN_TABLE_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIB_EDIT_PIN_TABLE_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxDataViewCtrl* m_Pins; + wxStdDialogButtonSizer* m_Buttons; + wxButton* m_ButtonsOK; + + // Virtual event handlers, overide them in your derived class + virtual void OnColumnHeaderRightClicked( wxDataViewEvent& event ) = 0; + + + public: + + DIALOG_LIB_EDIT_PIN_TABLE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pin Table"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 431,304 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIB_EDIT_PIN_TABLE_BASE(); + +}; + +#endif //__DIALOG_LIB_EDIT_PIN_TABLE_BASE_H__ diff --git a/eeschema/dialogs/dialog_lib_edit_text.cpp b/eeschema/dialogs/dialog_lib_edit_text.cpp new file mode 100644 index 00000000..a1c7ceea --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_text.cpp @@ -0,0 +1,222 @@ +/** + * @file dialog_lib_edit_text.cpp + * @brief dialog to editing graphic texts (not fields) in body components. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2001 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +DIALOG_LIB_EDIT_TEXT::DIALOG_LIB_EDIT_TEXT( LIB_EDIT_FRAME* aParent, LIB_TEXT* aText ) : + DIALOG_LIB_EDIT_TEXT_BASE( aParent ) +{ + m_parent = aParent; + m_graphicText = aText; + initDlg(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_LIB_EDIT_TEXT::initDlg( ) +{ + wxString msg; + + m_TextValue->SetFocus(); + + // Disable options for fieldedition, not existing in graphic text + m_Invisible->Show(false); + + if ( m_graphicText ) + { + msg = StringFromValue( g_UserUnit, m_graphicText->GetSize().x ); + m_TextSize->SetValue( msg ); + m_TextValue->SetValue( m_graphicText->GetText() ); + + if ( m_graphicText->GetUnit() == 0 ) + m_CommonUnit->SetValue( true ); + if ( m_graphicText->GetConvert() == 0 ) + m_CommonConvert->SetValue( true ); + if ( m_graphicText->GetOrientation() == TEXT_ORIENT_VERT ) + m_Orient->SetValue( true ); + + int shape = 0; + if ( m_graphicText->IsItalic() ) + shape = 1; + if ( m_graphicText->IsBold() ) + shape |= 2; + + m_TextShapeOpt->SetSelection( shape ); + + switch ( m_graphicText->GetHorizJustify() ) + { + case GR_TEXT_HJUSTIFY_LEFT: + m_TextHJustificationOpt->SetSelection( 0 ); + break; + + case GR_TEXT_HJUSTIFY_CENTER: + m_TextHJustificationOpt->SetSelection( 1 ); + break; + + case GR_TEXT_HJUSTIFY_RIGHT: + m_TextHJustificationOpt->SetSelection( 2 ); + break; + + } + + switch ( m_graphicText->GetVertJustify() ) + { + case GR_TEXT_VJUSTIFY_BOTTOM: + m_TextVJustificationOpt->SetSelection( 0 ); + break; + + case GR_TEXT_VJUSTIFY_CENTER: + m_TextVJustificationOpt->SetSelection( 1 ); + break; + + case GR_TEXT_VJUSTIFY_TOP: + m_TextVJustificationOpt->SetSelection( 2 ); + break; + } + } + else + { + msg = StringFromValue( g_UserUnit, m_parent->m_textSize ); + m_TextSize->SetValue( msg ); + + if ( ! m_parent->m_drawSpecificUnit ) + m_CommonUnit->SetValue( true ); + if ( ! m_parent->m_drawSpecificConvert ) + m_CommonConvert->SetValue( true ); + if ( m_parent->m_textOrientation == TEXT_ORIENT_VERT ) + m_Orient->SetValue( true ); + } + + msg = m_TextSizeText->GetLabel() + ReturnUnitSymbol(); + m_TextSizeText->SetLabel( msg ); + + m_sdbSizerButtonsOK->SetDefault(); + + // Hide the select button as the child dialog classes use this + m_TextValueSelectButton->Hide(); + + // Hide the "Power component value text cannot be modified!" warning + m_PowerComponentValues->Show( false ); + Fit(); +} + + +void DIALOG_LIB_EDIT_TEXT::OnCancelClick( wxCommandEvent& event ) +{ + EndModal(wxID_CANCEL); +} + + +/* Updates the different parameters for the component being edited */ +void DIALOG_LIB_EDIT_TEXT::OnOkClick( wxCommandEvent& event ) +{ + wxString Line; + + Line = m_TextValue->GetValue(); + m_parent->m_textOrientation = m_Orient->GetValue() ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ; + wxString msg = m_TextSize->GetValue(); + m_parent->m_textSize = ValueFromString( g_UserUnit, msg ); + m_parent->m_drawSpecificConvert = m_CommonConvert->GetValue() ? false : true; + m_parent->m_drawSpecificUnit = m_CommonUnit->GetValue() ? false : true; + + if( m_graphicText ) + { + if( ! Line.IsEmpty() ) + m_graphicText->SetText( Line ); + else + m_graphicText->SetText( wxT( "[null]" ) ); + + m_graphicText->SetSize( wxSize( m_parent->m_textSize, m_parent->m_textSize ) ); + m_graphicText->SetOrientation( m_parent->m_textOrientation ); + + if( m_parent->m_drawSpecificUnit ) + m_graphicText->SetUnit( m_parent->GetUnit() ); + else + m_graphicText->SetUnit( 0 ); + + if( m_parent->m_drawSpecificConvert ) + m_graphicText->SetConvert( m_parent->GetConvert() ); + else + m_graphicText->SetConvert( 0 ); + + m_graphicText->SetItalic( ( m_TextShapeOpt->GetSelection() & 1 ) != 0 ); + m_graphicText->SetBold( ( m_TextShapeOpt->GetSelection() & 2 ) != 0 ); + + switch( m_TextHJustificationOpt->GetSelection() ) + { + case 0: + m_graphicText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); + break; + + case 1: + m_graphicText->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER ); + break; + + case 2: + m_graphicText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); + break; + } + + switch( m_TextVJustificationOpt->GetSelection() ) + { + case 0: + m_graphicText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); + break; + + case 1: + m_graphicText->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER ); + break; + + case 2: + m_graphicText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); + break; + } + } + + if( m_parent->GetDrawItem() ) + m_parent->SetMsgPanel( m_parent->GetDrawItem() ); + + EndModal(wxID_OK); +} diff --git a/eeschema/dialogs/dialog_lib_edit_text.h b/eeschema/dialogs/dialog_lib_edit_text.h new file mode 100644 index 00000000..24ad5899 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_text.h @@ -0,0 +1,54 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2001 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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_LIB_EDIT_TEXT_H_ +#define _DIALOG_LIB_EDIT_TEXT_H_ + + +#include + + +class LIB_EDIT_FRAME; +class LIB_TEXT; + + +class DIALOG_LIB_EDIT_TEXT : public DIALOG_LIB_EDIT_TEXT_BASE +{ +private: + LIB_EDIT_FRAME* m_parent; + LIB_TEXT* m_graphicText; + +public: + DIALOG_LIB_EDIT_TEXT( LIB_EDIT_FRAME* aParent, LIB_TEXT* aText ); + ~DIALOG_LIB_EDIT_TEXT() {}; + +private: + void initDlg( ); + void OnOkClick( wxCommandEvent& aEvent ); + void OnCancelClick( wxCommandEvent& aEvent ); +}; + + +#endif // _DIALOG_LIB_EDIT_TEXT_H_ diff --git a/eeschema/dialogs/dialog_lib_edit_text_base.cpp b/eeschema/dialogs/dialog_lib_edit_text_base.cpp new file mode 100644 index 00000000..5ba9cd5f --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_text_base.cpp @@ -0,0 +1,150 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_lib_edit_text_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIB_EDIT_TEXT_BASE::DIALOG_LIB_EDIT_TEXT_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bPropertiesSizer; + bPropertiesSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bUpperBoxSizer; + bUpperBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bTextValueBoxSizer; + bTextValueBoxSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("Text"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + bTextValueBoxSizer->Add( m_staticText1, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bTextValueOptsSizer; + bTextValueOptsSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_TextValue = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_TextValue->SetMaxLength( 0 ); + m_TextValue->SetMinSize( wxSize( 200,-1 ) ); + + bTextValueOptsSizer->Add( m_TextValue, 1, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5 ); + + m_TextValueSelectButton = new wxButton( this, wxID_ANY, _("Select"), wxDefaultPosition, wxDefaultSize, 0 ); + bTextValueOptsSizer->Add( m_TextValueSelectButton, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bTextValueBoxSizer->Add( bTextValueOptsSizer, 1, wxEXPAND, 5 ); + + + bUpperBoxSizer->Add( bTextValueBoxSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bTextSizeSizer; + bTextSizeSizer = new wxBoxSizer( wxVERTICAL ); + + m_TextSizeText = new wxStaticText( this, wxID_ANY, _("Size"), wxDefaultPosition, wxDefaultSize, 0 ); + m_TextSizeText->Wrap( -1 ); + bTextSizeSizer->Add( m_TextSizeText, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_TextSize = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_TextSize->SetMaxLength( 0 ); + bTextSizeSizer->Add( m_TextSize, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP, 5 ); + + + bUpperBoxSizer->Add( bTextSizeSizer, 0, wxEXPAND, 5 ); + + + bPropertiesSizer->Add( bUpperBoxSizer, 0, wxEXPAND, 5 ); + + m_PowerComponentValues = new wxStaticText( this, wxID_ANY, _("Power component value text cannot be modified!"), wxDefaultPosition, wxDefaultSize, 0 ); + m_PowerComponentValues->Wrap( -1 ); + m_PowerComponentValues->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bPropertiesSizer->Add( m_PowerComponentValues, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bBottomtBoxSizer; + bBottomtBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticBoxSizer* sOptionsSizer; + sOptionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Options") ), wxVERTICAL ); + + m_Orient = new wxCheckBox( this, wxID_ANY, _("Vertical"), wxDefaultPosition, wxDefaultSize, 0 ); + sOptionsSizer->Add( m_Orient, 0, wxALL, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + sOptionsSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_CommonUnit = new wxCheckBox( this, wxID_ANY, _("Common to all units"), wxDefaultPosition, wxDefaultSize, 0 ); + sOptionsSizer->Add( m_CommonUnit, 0, wxALL, 5 ); + + m_CommonConvert = new wxCheckBox( this, wxID_ANY, _("Common to all body styles"), wxDefaultPosition, wxDefaultSize, 0 ); + sOptionsSizer->Add( m_CommonConvert, 0, wxALL|wxEXPAND, 5 ); + + m_Invisible = new wxCheckBox( this, wxID_ANY, _("Invisible"), wxDefaultPosition, wxDefaultSize, 0 ); + sOptionsSizer->Add( m_Invisible, 0, wxALL, 5 ); + + + bBottomtBoxSizer->Add( sOptionsSizer, 0, wxALL|wxEXPAND, 5 ); + + wxString m_TextShapeOptChoices[] = { _("Normal"), _("Italic"), _("Bold"), _("Bold Italic") }; + int m_TextShapeOptNChoices = sizeof( m_TextShapeOptChoices ) / sizeof( wxString ); + m_TextShapeOpt = new wxRadioBox( this, wxID_ANY, _("Style"), wxDefaultPosition, wxDefaultSize, m_TextShapeOptNChoices, m_TextShapeOptChoices, 1, wxRA_SPECIFY_COLS ); + m_TextShapeOpt->SetSelection( 0 ); + bBottomtBoxSizer->Add( m_TextShapeOpt, 1, wxALL|wxEXPAND, 5 ); + + wxString m_TextHJustificationOptChoices[] = { _("Align left"), _("Align center"), _("Align right") }; + int m_TextHJustificationOptNChoices = sizeof( m_TextHJustificationOptChoices ) / sizeof( wxString ); + m_TextHJustificationOpt = new wxRadioBox( this, wxID_ANY, _("Horizontal Justify"), wxDefaultPosition, wxDefaultSize, m_TextHJustificationOptNChoices, m_TextHJustificationOptChoices, 1, wxRA_SPECIFY_COLS ); + m_TextHJustificationOpt->SetSelection( 1 ); + bBottomtBoxSizer->Add( m_TextHJustificationOpt, 1, wxALL|wxEXPAND, 5 ); + + wxString m_TextVJustificationOptChoices[] = { _("Align bottom"), _("Align center"), _("Align top") }; + int m_TextVJustificationOptNChoices = sizeof( m_TextVJustificationOptChoices ) / sizeof( wxString ); + m_TextVJustificationOpt = new wxRadioBox( this, wxID_ANY, _("Vertical Justify"), wxDefaultPosition, wxDefaultSize, m_TextVJustificationOptNChoices, m_TextVJustificationOptChoices, 1, wxRA_SPECIFY_COLS ); + m_TextVJustificationOpt->SetSelection( 1 ); + bBottomtBoxSizer->Add( m_TextVJustificationOpt, 1, wxALL|wxEXPAND, 5 ); + + + bPropertiesSizer->Add( bBottomtBoxSizer, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bPropertiesSizer, 1, wxEXPAND, 6 ); + + m_sdbSizerButtons = new wxStdDialogButtonSizer(); + m_sdbSizerButtonsOK = new wxButton( this, wxID_OK ); + m_sdbSizerButtons->AddButton( m_sdbSizerButtonsOK ); + m_sdbSizerButtonsCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizerButtons->AddButton( m_sdbSizerButtonsCancel ); + m_sdbSizerButtons->Realize(); + + bMainSizer->Add( m_sdbSizerButtons, 0, wxBOTTOM|wxEXPAND|wxTOP, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnCloseDialog ) ); + m_TextValueSelectButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnTextValueSelectButtonClick ), NULL, this ); + m_sdbSizerButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_LIB_EDIT_TEXT_BASE::~DIALOG_LIB_EDIT_TEXT_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnCloseDialog ) ); + m_TextValueSelectButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnTextValueSelectButtonClick ), NULL, this ); + m_sdbSizerButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_TEXT_BASE::OnOkClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_lib_edit_text_base.fbp b/eeschema/dialogs/dialog_lib_edit_text_base.fbp new file mode 100644 index 00000000..d48e9be0 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_text_base.fbp @@ -0,0 +1,1427 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_lib_edit_text_base + 1000 + none + 1 + DIALOG_LIB_EDIT_TEXT_BASE + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIB_EDIT_TEXT_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Library Text Properties + + + + + + + + + + + + + + OnCloseDialog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 6 + wxEXPAND + 1 + + + bPropertiesSizer + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bUpperBoxSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bTextValueBoxSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bTextValueOptsSizer + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + 200,-1 + 1 + m_TextValue + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select + + 0 + + + 0 + + 1 + m_TextValueSelectButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnTextValueSelectButtonClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bTextSizeSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size + + 0 + + + 0 + + 1 + m_TextSizeText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_TextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Power component value text cannot be modified! + + 0 + + + 0 + + 1 + m_PowerComponentValues + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bBottomtBoxSizer + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + Options + + sOptionsSizer + wxVERTICAL + none + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Vertical + + 0 + + + 0 + + 1 + m_Orient + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all units + + 0 + + + 0 + + 1 + m_CommonUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Common to all body styles + + 0 + + + 0 + + 1 + m_CommonConvert + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Invisible + + 0 + + + 0 + + 1 + m_Invisible + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Normal" "Italic" "Bold" "Bold Italic" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Style + 1 + + 0 + + + 0 + + 1 + m_TextShapeOpt + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Align left" "Align center" "Align right" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Horizontal Justify + 1 + + 0 + + + 0 + + 1 + m_TextHJustificationOpt + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Align bottom" "Align center" "Align top" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Vertical Justify + 1 + + 0 + + + 0 + + 1 + m_TextVJustificationOpt + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxTOP + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizerButtons + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_edit_text_base.h b/eeschema/dialogs/dialog_lib_edit_text_base.h new file mode 100644 index 00000000..cb1964b7 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_edit_text_base.h @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIB_EDIT_TEXT_BASE_H__ +#define __DIALOG_LIB_EDIT_TEXT_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIB_EDIT_TEXT_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIB_EDIT_TEXT_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText1; + wxTextCtrl* m_TextValue; + wxButton* m_TextValueSelectButton; + wxStaticText* m_TextSizeText; + wxTextCtrl* m_TextSize; + wxStaticText* m_PowerComponentValues; + wxCheckBox* m_Orient; + wxStaticLine* m_staticline1; + wxCheckBox* m_CommonUnit; + wxCheckBox* m_CommonConvert; + wxCheckBox* m_Invisible; + wxRadioBox* m_TextShapeOpt; + wxRadioBox* m_TextHJustificationOpt; + wxRadioBox* m_TextVJustificationOpt; + wxStdDialogButtonSizer* m_sdbSizerButtons; + wxButton* m_sdbSizerButtonsOK; + wxButton* m_sdbSizerButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); } + virtual void OnTextValueSelectButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_LIB_EDIT_TEXT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Library Text Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIB_EDIT_TEXT_BASE(); + +}; + +#endif //__DIALOG_LIB_EDIT_TEXT_BASE_H__ diff --git a/eeschema/dialogs/dialog_lib_new_component.cpp b/eeschema/dialogs/dialog_lib_new_component.cpp new file mode 100644 index 00000000..23ddad8e --- /dev/null +++ b/eeschema/dialogs/dialog_lib_new_component.cpp @@ -0,0 +1,45 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2016 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 +#include +#include + +DIALOG_LIB_NEW_COMPONENT::DIALOG_LIB_NEW_COMPONENT( wxWindow* parent ) : + DIALOG_LIB_NEW_COMPONENT_BASE( parent ) +{ + m_textName->SetValidator( SCH_FIELD_VALIDATOR( true, VALUE ) ); + m_textReference->SetValidator( SCH_FIELD_VALIDATOR( true, REFERENCE ) ); + + // initial focus should be on first editable field. + m_textName->SetFocus(); + + // What happens when user presses "Enter"? OK button! OK? + m_sdbSizerOK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} diff --git a/eeschema/dialogs/dialog_lib_new_component.fbp b/eeschema/dialogs/dialog_lib_new_component.fbp new file mode 100644 index 00000000..01560a97 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_new_component.fbp @@ -0,0 +1,1597 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + table + dialog_lib_new_component_base + 1000 + none + 1 + dialog_lib_new_component + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIB_NEW_COMPONENT_BASE + + + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Component Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer7 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + + bSizer16 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + General Settings + + 0 + + + 0 + + 1 + m_staticText8 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + wxEXPAND|wxLEFT|wxRIGHT + 1 + + 2 + wxBOTH + 1 + + 0 + + fgSizer31 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Component &name: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + This is the component name in library, and also the default component value when loaded in the schematic. + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textName + 1 + + + protected + 1 + + Resizable + 1 + 100,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Default reference designator: + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textReference + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + U + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Number of units per package: + + 0 + + + 0 + + 1 + m_staticText10 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 26 + + 0 + + 1 + + 0 + + 1 + m_spinPartCount + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 + wxEXPAND|wxLEFT|wxRIGHT + 1 + + + bSizer17 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Create component with alternate body style (DeMorgan) + + 0 + + + 0 + + 1 + m_checkHasConversion + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Create component as power symbol + + 0 + + + 0 + + 1 + m_checkIsPowerSymbol + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Units are not interchangeable + + 0 + + + 0 + + 1 + m_checkLockItems + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + bSizer18 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 10 + protected + 0 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + General Pin Settings + + 0 + + + 0 + + 1 + m_staticText11 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + wxLEFT|wxRIGHT + 0 + + 2 + wxBOTH + + + 55 + + fgSizer4 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pin text position offset: + + 0 + + + 0 + + 1 + m_staticText12 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 40 + 100 + + 0 + + 1 + + 0 + + 1 + m_spinPinTextPosition + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + 40 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 + wxEXPAND|wxLEFT|wxRIGHT + 0 + + + bSizer19 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show pin number text + + 0 + + + 0 + + 1 + m_checkShowPinNumber + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show pin name text + + 0 + + + 0 + + 1 + m_checkShowPinName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pin name inside + + 0 + + + 0 + + 1 + m_checkShowPinNameInside + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_new_component.h b/eeschema/dialogs/dialog_lib_new_component.h new file mode 100644 index 00000000..b8b9619f --- /dev/null +++ b/eeschema/dialogs/dialog_lib_new_component.h @@ -0,0 +1,97 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009-2105 Wayne Stambaugh + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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_lib_new_component__ +#define __dialog_lib_new_component__ + +/** + * @file + * Subclass of DIALOG_LIB_NEW_COMPONENT, which is generated by wxFormBuilder. + */ + +#include + +/** Implementing DIALOG_LIB_NEW_COMPONENT */ +class DIALOG_LIB_NEW_COMPONENT : public DIALOG_LIB_NEW_COMPONENT_BASE +{ +public: + /** Constructor */ + DIALOG_LIB_NEW_COMPONENT( wxWindow* parent ); + + void SetName( const wxString& name ) { m_textName->SetValue( name ); } + wxString GetName( void ) const { return m_textName->GetValue(); } + + void SetReference( const wxString& reference ) + { + m_textReference->SetValue( reference ); + } + wxString GetReference( void ) { return m_textReference->GetValue(); } + + void SetPartCount( int count ) { m_spinPartCount->SetValue( count ); } + int GetUnitCount( void ) { return m_spinPartCount->GetValue(); } + + void SetAlternateBodyStyle( bool enable ) + { + m_checkHasConversion->SetValue( enable ); + } + bool GetAlternateBodyStyle( void ) + { + return m_checkHasConversion->GetValue(); + } + + void SetPowerSymbol( bool enable ) + { + m_checkIsPowerSymbol->SetValue( enable ); + } + bool GetPowerSymbol( void ) { return m_checkIsPowerSymbol->GetValue(); } + + void SetLockItems( bool enable ) { m_checkLockItems->SetValue( enable ); } + bool GetLockItems( void ) { return m_checkLockItems->GetValue(); } + + void SetPinTextPosition( int position ) + { + m_spinPinTextPosition->SetValue( position ); + } + int GetPinTextPosition( void ) { return m_spinPinTextPosition->GetValue(); } + + void SetShowPinNumber( bool show ) + { + m_checkShowPinNumber->SetValue( show ); + } + bool GetShowPinNumber( void ) { return m_checkShowPinNumber->GetValue(); } + + void SetShowPinName( bool show ) + { + m_checkShowPinName->SetValue( show ); + } + bool GetShowPinName( void ) { return m_checkShowPinName->GetValue(); } + + void SetPinNameInside( bool show ) + { + m_checkShowPinNameInside->SetValue( show ); + } + bool GetPinNameInside( void ) { return m_checkShowPinNameInside->GetValue(); } +}; + +#endif // __dialog_lib_new_component__ diff --git a/eeschema/dialogs/dialog_lib_new_component_base.cpp b/eeschema/dialogs/dialog_lib_new_component_base.cpp new file mode 100644 index 00000000..35910e80 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_new_component_base.cpp @@ -0,0 +1,146 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_lib_new_component_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIB_NEW_COMPONENT_BASE::DIALOG_LIB_NEW_COMPONENT_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizer7; + bSizer7 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer16; + bSizer16 = new wxBoxSizer( wxVERTICAL ); + + m_staticText8 = new wxStaticText( this, wxID_ANY, _("General Settings"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText8->Wrap( -1 ); + m_staticText8->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizer16->Add( m_staticText8, 0, wxALL, 5 ); + + wxFlexGridSizer* fgSizer31; + fgSizer31 = new wxFlexGridSizer( 0, 2, 0, 0 ); + fgSizer31->AddGrowableCol( 1 ); + fgSizer31->SetFlexibleDirection( wxBOTH ); + fgSizer31->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText2 = new wxStaticText( this, wxID_ANY, _("Component &name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + m_staticText2->SetToolTip( _("This is the component name in library,\nand also the default component value when loaded in the schematic.") ); + + fgSizer31->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 100,-1 ), 0 ); + m_textName->SetMaxLength( 0 ); + fgSizer31->Add( m_textName, 1, wxALL|wxEXPAND, 3 ); + + m_staticText9 = new wxStaticText( this, wxID_ANY, _("Default reference designator:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText9->Wrap( -1 ); + fgSizer31->Add( m_staticText9, 0, wxALL, 5 ); + + m_textReference = new wxTextCtrl( this, wxID_ANY, _("U"), wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer31->Add( m_textReference, 0, wxALL|wxEXPAND, 5 ); + + m_staticText10 = new wxStaticText( this, wxID_ANY, _("Number of units per package:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText10->Wrap( -1 ); + fgSizer31->Add( m_staticText10, 0, wxALL, 5 ); + + m_spinPartCount = new wxSpinCtrl( this, wxID_ANY, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 26, 0 ); + fgSizer31->Add( m_spinPartCount, 0, wxALL, 5 ); + + + bSizer16->Add( fgSizer31, 1, wxEXPAND|wxLEFT|wxRIGHT, 20 ); + + wxBoxSizer* bSizer17; + bSizer17 = new wxBoxSizer( wxVERTICAL ); + + m_checkHasConversion = new wxCheckBox( this, wxID_ANY, _("Create component with alternate body style (DeMorgan)"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer17->Add( m_checkHasConversion, 0, wxALL, 5 ); + + m_checkIsPowerSymbol = new wxCheckBox( this, wxID_ANY, _("Create component as power symbol"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer17->Add( m_checkIsPowerSymbol, 0, wxALL, 5 ); + + m_checkLockItems = new wxCheckBox( this, wxID_ANY, _("Units are not interchangeable"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer17->Add( m_checkLockItems, 0, wxALL, 5 ); + + + bSizer16->Add( bSizer17, 1, wxEXPAND|wxLEFT|wxRIGHT, 15 ); + + + bSizer7->Add( bSizer16, 0, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bSizer18; + bSizer18 = new wxBoxSizer( wxVERTICAL ); + + + bSizer18->Add( 0, 10, 0, wxEXPAND, 5 ); + + m_staticText11 = new wxStaticText( this, wxID_ANY, _("General Pin Settings"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText11->Wrap( -1 ); + m_staticText11->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizer18->Add( m_staticText11, 0, wxALL, 5 ); + + wxFlexGridSizer* fgSizer4; + fgSizer4 = new wxFlexGridSizer( 0, 2, 0, 55 ); + fgSizer4->SetFlexibleDirection( wxBOTH ); + fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText12 = new wxStaticText( this, wxID_ANY, _("Pin text position offset:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText12->Wrap( -1 ); + fgSizer4->Add( m_staticText12, 0, wxALL, 5 ); + + m_spinPinTextPosition = new wxSpinCtrl( this, wxID_ANY, wxT("40"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 40 ); + fgSizer4->Add( m_spinPinTextPosition, 0, wxALL, 5 ); + + + bSizer18->Add( fgSizer4, 0, wxLEFT|wxRIGHT, 20 ); + + wxBoxSizer* bSizer19; + bSizer19 = new wxBoxSizer( wxVERTICAL ); + + m_checkShowPinNumber = new wxCheckBox( this, wxID_ANY, _("Show pin number text"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkShowPinNumber->SetValue(true); + bSizer19->Add( m_checkShowPinNumber, 0, wxALL, 5 ); + + m_checkShowPinName = new wxCheckBox( this, wxID_ANY, _("Show pin name text"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkShowPinName->SetValue(true); + bSizer19->Add( m_checkShowPinName, 0, wxALL, 5 ); + + m_checkShowPinNameInside = new wxCheckBox( this, wxID_ANY, _("Pin name inside"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkShowPinNameInside->SetValue(true); + bSizer19->Add( m_checkShowPinNameInside, 0, wxALL, 5 ); + + + bSizer18->Add( bSizer19, 0, wxEXPAND|wxLEFT|wxRIGHT, 15 ); + + + bSizer7->Add( bSizer18, 1, wxALL|wxEXPAND, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + bSizer7->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 10 ); + + + this->SetSizer( bSizer7 ); + this->Layout(); + bSizer7->Fit( this ); + + this->Centre( wxBOTH ); +} + +DIALOG_LIB_NEW_COMPONENT_BASE::~DIALOG_LIB_NEW_COMPONENT_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_lib_new_component_base.h b/eeschema/dialogs/dialog_lib_new_component_base.h new file mode 100644 index 00000000..e90c52c0 --- /dev/null +++ b/eeschema/dialogs/dialog_lib_new_component_base.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIB_NEW_COMPONENT_BASE_H__ +#define __DIALOG_LIB_NEW_COMPONENT_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIB_NEW_COMPONENT_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIB_NEW_COMPONENT_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText8; + wxStaticText* m_staticText2; + wxTextCtrl* m_textName; + wxStaticText* m_staticText9; + wxTextCtrl* m_textReference; + wxStaticText* m_staticText10; + wxSpinCtrl* m_spinPartCount; + wxCheckBox* m_checkHasConversion; + wxCheckBox* m_checkIsPowerSymbol; + wxCheckBox* m_checkLockItems; + wxStaticText* m_staticText11; + wxStaticText* m_staticText12; + wxSpinCtrl* m_spinPinTextPosition; + wxCheckBox* m_checkShowPinNumber; + wxCheckBox* m_checkShowPinName; + wxCheckBox* m_checkShowPinNameInside; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + public: + + DIALOG_LIB_NEW_COMPONENT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Component Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIB_NEW_COMPONENT_BASE(); + +}; + +#endif //__DIALOG_LIB_NEW_COMPONENT_BASE_H__ diff --git a/eeschema/dialogs/dialog_libedit_options.cpp b/eeschema/dialogs/dialog_libedit_options.cpp new file mode 100644 index 00000000..4506d772 --- /dev/null +++ b/eeschema/dialogs/dialog_libedit_options.cpp @@ -0,0 +1,69 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2011 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 + */ + +/** + * @file dialog_libedit_options.cpp + */ + +#include +#include + +#include +#include + + +DIALOG_LIBEDIT_OPTIONS::DIALOG_LIBEDIT_OPTIONS( LIB_EDIT_FRAME* parent ) : + DIALOG_LIBEDIT_OPTIONS_BASE( parent ) +{ + m_sdbSizerOK->SetDefault(); + + SetRepeatLabelInc( Parent()->GetRepeatDeltaLabel() ); + SetItemRepeatStep( Parent()->GetRepeatStep() ); + SetPinRepeatStep( Parent()->GetRepeatPinStep() ); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + +void DIALOG_LIBEDIT_OPTIONS::SetGridSizes( const GRIDS& grid_sizes, int grid_id ) +{ + wxASSERT( grid_sizes.size() > 0 ); + + int select = wxNOT_FOUND; + + for( size_t i = 0; i < grid_sizes.size(); i++ ) + { + wxString tmp; + tmp.Printf( wxT( "%0.1f" ), grid_sizes[i].m_Size.x ); + m_choiceGridSize->Append( tmp ); + + if( grid_sizes[i].m_CmdId == grid_id ) + select = (int) i; + } + + m_choiceGridSize->SetSelection( select ); +} diff --git a/eeschema/dialogs/dialog_libedit_options.h b/eeschema/dialogs/dialog_libedit_options.h new file mode 100644 index 00000000..02ac67e3 --- /dev/null +++ b/eeschema/dialogs/dialog_libedit_options.h @@ -0,0 +1,93 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file dialog_libedit_options.h + * + * Subclass of DIALOG_LIBEDIT_OPTIONS_BASE, which is generated by wxFormBuilder. + */ + +#ifndef __DIALOG_LIBEDIT_OPTIONS__ +#define __DIALOG_LIBEDIT_OPTIONS__ + +#include + +class LIB_EDIT_FRAME; + +class DIALOG_LIBEDIT_OPTIONS : public DIALOG_LIBEDIT_OPTIONS_BASE +{ +public: + DIALOG_LIBEDIT_OPTIONS( LIB_EDIT_FRAME* parent ); + + LIB_EDIT_FRAME* Parent() { return (LIB_EDIT_FRAME*) GetParent(); } + + void SetGridSelection( int select ) { m_choiceGridSize->SetSelection( select ); } + int GetGridSelection( void ) { return m_choiceGridSize->GetSelection(); } + void SetGridSizes( const GRIDS& grid_sizes, int grid_id ); + + void SetShowGrid( bool show ) { m_checkShowGrid->SetValue( show ); } + bool GetShowGrid( void ) { return m_checkShowGrid->GetValue(); } + + void SetLineWidth( int aWidth ) { m_spinLineWidth->SetValue( aWidth ); } + int GetLineWidth( void ) { return m_spinLineWidth->GetValue(); } + + void SetPinLength( int aLength ) { m_spinPinLength->SetValue( aLength ); } + int GetPinLength( void ) { return m_spinPinLength->GetValue(); } + + void SetPinNumSize( int text_size ) { m_spinPinNumSize->SetValue( text_size ); } + int GetPinNumSize( void ) { return m_spinPinNumSize->GetValue(); } + + void SetPinNameSize( int text_size ) { m_spinPinNameSize->SetValue( text_size ); } + int GetPinNameSize( void ) { return m_spinPinNameSize->GetValue(); } + + void SetPinRepeatStep( int aValue ) { m_choicePinDisplacement->SetSelection( aValue == 50 ? 1 : 0 ); } + int GetPinRepeatStep( void ) + { + return m_choicePinDisplacement->GetSelection() == 1 ? 50 : 100; + } + + void SetItemRepeatStep( wxPoint aValue ) + { + m_spinRepeatHorizontal->SetValue( aValue.x ); + m_spinRepeatVertical->SetValue( aValue.y ); + } + wxPoint GetItemRepeatStep( void ) + { + wxPoint step; + step.x = m_spinRepeatHorizontal->GetValue(); + step.y = m_spinRepeatVertical->GetValue(); + return step; + } + + void SetRepeatLabelInc( int aValue ) { m_spinRepeatLabel->SetValue( aValue ); } + int GetRepeatLabelInc( void ) + { + return m_spinRepeatLabel->GetValue(); + } + + void SetMaxUndoItems( int aItems ) { m_spinMaxUndoItems->SetValue( aItems ); } + int GetMaxUndoItems() const { return m_spinMaxUndoItems->GetValue(); } +}; + +#endif // __DIALOG_LIBEDIT_OPTIONS__ diff --git a/eeschema/dialogs/dialog_libedit_options_base.cpp b/eeschema/dialogs/dialog_libedit_options_base.cpp new file mode 100644 index 00000000..20205716 --- /dev/null +++ b/eeschema/dialogs/dialog_libedit_options_base.cpp @@ -0,0 +1,195 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 13 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_libedit_options_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LIBEDIT_OPTIONS_BASE::DIALOG_LIBEDIT_OPTIONS_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bOptionsSizer; + bOptionsSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* p1mainSizer; + p1mainSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizer; + fgSizer = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer->AddGrowableCol( 0 ); + fgSizer->AddGrowableCol( 1 ); + fgSizer->AddGrowableCol( 2 ); + fgSizer->SetFlexibleDirection( wxBOTH ); + fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText3 = new wxStaticText( this, wxID_ANY, _("&Grid size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + fgSizer->Add( m_staticText3, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + wxArrayString m_choiceGridSizeChoices; + m_choiceGridSize = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceGridSizeChoices, 0 ); + m_choiceGridSize->SetSelection( 0 ); + fgSizer->Add( m_choiceGridSize, 0, wxEXPAND|wxALL, 3 ); + + m_staticGridUnits = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticGridUnits->Wrap( -1 ); + fgSizer->Add( m_staticGridUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText5 = new wxStaticText( this, wxID_ANY, _("&Default line width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + fgSizer->Add( m_staticText5, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinLineWidth = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 1, 100, 6 ); + fgSizer->Add( m_spinLineWidth, 0, wxALL|wxEXPAND, 3 ); + + m_staticLineWidthUnits = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticLineWidthUnits->Wrap( -1 ); + fgSizer->Add( m_staticLineWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText52 = new wxStaticText( this, wxID_ANY, _("D&efault pin length:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText52->Wrap( -1 ); + fgSizer->Add( m_staticText52, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 3 ); + + m_spinPinLength = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 50, 1000, 200 ); + fgSizer->Add( m_spinPinLength, 0, wxALL|wxEXPAND, 3 ); + + m_staticPinLengthUnits = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticPinLengthUnits->Wrap( -1 ); + fgSizer->Add( m_staticPinLengthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 3 ); + + m_staticText7 = new wxStaticText( this, wxID_ANY, _("De&fault pin number size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText7->Wrap( -1 ); + fgSizer->Add( m_staticText7, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinPinNumSize = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 0, 1000, 0 ); + fgSizer->Add( m_spinPinNumSize, 0, wxALL|wxEXPAND, 3 ); + + m_staticTextSizeUnits = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSizeUnits->Wrap( -1 ); + fgSizer->Add( m_staticTextSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText9 = new wxStaticText( this, wxID_ANY, _("Def&ault pin name size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText9->Wrap( -1 ); + fgSizer->Add( m_staticText9, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_spinPinNameSize = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, -5000, 5000, 0 ); + fgSizer->Add( m_spinPinNameSize, 0, wxALL|wxEXPAND, 3 ); + + m_staticRepeatXUnits = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticRepeatXUnits->Wrap( -1 ); + fgSizer->Add( m_staticRepeatXUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + + m_staticText11 = new wxStaticText( this, wxID_ANY, _("&Horizontal pitch of repeated items:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText11->Wrap( -1 ); + fgSizer->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_spinRepeatHorizontal = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -1000, 1000, 0 ); + fgSizer->Add( m_spinRepeatHorizontal, 0, wxALL|wxEXPAND, 5 ); + + m_staticText12 = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText12->Wrap( -1 ); + fgSizer->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_staticText13 = new wxStaticText( this, wxID_ANY, _("&Vertical pitch of repeated items:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText13->Wrap( -1 ); + fgSizer->Add( m_staticText13, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_spinRepeatVertical = new wxSpinCtrl( this, wxID_ANY, wxT("100"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -1000, 1000, 0 ); + fgSizer->Add( m_spinRepeatVertical, 0, wxALL|wxEXPAND, 5 ); + + m_staticText14 = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText14->Wrap( -1 ); + fgSizer->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_staticText15 = new wxStaticText( this, wxID_ANY, _("&Pitch of repeated pins:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText15->Wrap( -1 ); + fgSizer->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxString m_choicePinDisplacementChoices[] = { _("100"), _("50") }; + int m_choicePinDisplacementNChoices = sizeof( m_choicePinDisplacementChoices ) / sizeof( wxString ); + m_choicePinDisplacement = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePinDisplacementNChoices, m_choicePinDisplacementChoices, 0 ); + m_choicePinDisplacement->SetSelection( 0 ); + fgSizer->Add( m_choicePinDisplacement, 0, wxALL|wxEXPAND, 5 ); + + m_staticText16 = new wxStaticText( this, wxID_ANY, _("mils"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText16->Wrap( -1 ); + fgSizer->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_staticText17 = new wxStaticText( this, wxID_ANY, _("&Increment of repeated labels:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText17->Wrap( -1 ); + fgSizer->Add( m_staticText17, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_spinRepeatLabel = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -10, 10, 1 ); + fgSizer->Add( m_spinRepeatLabel, 0, wxALL|wxEXPAND, 5 ); + + + fgSizer->Add( 0, 0, 0, 0, 5 ); + + m_stMaxUndoItems = new wxStaticText( this, wxID_ANY, _("Ma&ximum undo items (0 = unlimited):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_stMaxUndoItems->Wrap( -1 ); + fgSizer->Add( m_stMaxUndoItems, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_spinMaxUndoItems = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 65536, 0 ); + fgSizer->Add( m_spinMaxUndoItems, 0, wxALL|wxEXPAND, 5 ); + + m_stMaxUndoItemsUnit = new wxStaticText( this, wxID_ANY, _("actions"), wxDefaultPosition, wxDefaultSize, 0 ); + m_stMaxUndoItemsUnit->Wrap( -1 ); + fgSizer->Add( m_stMaxUndoItemsUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bSizer3->Add( fgSizer, 0, wxEXPAND, 0 ); + + wxBoxSizer* bSizer2; + bSizer2 = new wxBoxSizer( wxVERTICAL ); + + m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizer2->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 ); + + m_checkShowGrid = new wxCheckBox( this, wxID_ANY, _("&Show grid"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_checkShowGrid, 0, wxTOP|wxRIGHT|wxLEFT|wxEXPAND, 3 ); + + + bSizer3->Add( bSizer2, 0, wxEXPAND, 0 ); + + + p1mainSizer->Add( bSizer3, 1, wxALL|wxEXPAND, 6 ); + + + bOptionsSizer->Add( p1mainSizer, 1, wxEXPAND, 5 ); + + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bOptionsSizer->Add( m_staticline2, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + bOptionsSizer->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 6 ); + + + mainSizer->Add( bOptionsSizer, 1, wxEXPAND, 12 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +DIALOG_LIBEDIT_OPTIONS_BASE::~DIALOG_LIBEDIT_OPTIONS_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_libedit_options_base.fbp b/eeschema/dialogs/dialog_libedit_options_base.fbp new file mode 100644 index 00000000..3321b658 --- /dev/null +++ b/eeschema/dialogs/dialog_libedit_options_base.fbp @@ -0,0 +1,2904 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + table + dialog_libedit_options_base + 1000 + none + 1 + dialog_libedit_options + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LIBEDIT_OPTIONS_BASE + + 487,433 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Library Editor Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 12 + wxEXPAND + 1 + + + bOptionsSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + p1mainSizer + wxHORIZONTAL + none + + 6 + wxALL|wxEXPAND + 1 + + + bSizer3 + wxVERTICAL + none + + 0 + wxEXPAND + 0 + + 3 + wxBOTH + 0,1,2 + + 0 + + fgSizer + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Grid size: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceGridSize + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticGridUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Default line width: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 6 + 100 + + 0 + + 1 + + 0 + + 1 + m_spinLineWidth + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticLineWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + D&efault pin length: + + 0 + + + 0 + + 1 + m_staticText52 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 200 + 1000 + + 0 + + 50 + + 0 + + 1 + m_spinPinLength + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticPinLengthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + De&fault pin number size: + + 0 + + + 0 + + 1 + m_staticText7 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 1000 + + 0 + + 0 + + 0 + + 1 + m_spinPinNumSize + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticTextSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Def&ault pin name size: + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 5000 + + 0 + + -5000 + + 0 + + 1 + m_spinPinNameSize + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS|wxSP_WRAP + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticRepeatXUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Horizontal pitch of repeated items: + + 0 + + + 0 + + 1 + m_staticText11 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 1000 + + 0 + + -1000 + + 0 + + 1 + m_spinRepeatHorizontal + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticText12 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Vertical pitch of repeated items: + + 0 + + + 0 + + 1 + m_staticText13 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 1000 + + 0 + + -1000 + + 0 + + 1 + m_spinRepeatVertical + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticText14 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Pitch of repeated pins: + + 0 + + + 0 + + 1 + m_staticText15 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "100" "50" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choicePinDisplacement + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mils + + 0 + + + 0 + + 1 + m_staticText16 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Increment of repeated labels: + + 0 + + + 0 + + 1 + m_staticText17 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 1 + 10 + + 0 + + -10 + + 0 + + 1 + m_spinRepeatLabel + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + 0 + + 0 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Ma&ximum undo items (0 = unlimited): + + 0 + + + 0 + + 1 + m_stMaxUndoItems + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 65536 + + 0 + + 0 + + 0 + + 1 + m_spinMaxUndoItems + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + actions + + 0 + + + 0 + + 1 + m_stMaxUndoItemsUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxEXPAND + 0 + + + bSizer2 + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline3 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxTOP|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Show grid + + 0 + + + 0 + + 1 + m_checkShowGrid + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_libedit_options_base.h b/eeschema/dialogs/dialog_libedit_options_base.h new file mode 100644 index 00000000..9764e6f2 --- /dev/null +++ b/eeschema/dialogs/dialog_libedit_options_base.h @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 13 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LIBEDIT_OPTIONS_BASE_H__ +#define __DIALOG_LIBEDIT_OPTIONS_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LIBEDIT_OPTIONS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LIBEDIT_OPTIONS_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText3; + wxChoice* m_choiceGridSize; + wxStaticText* m_staticGridUnits; + wxStaticText* m_staticText5; + wxSpinCtrl* m_spinLineWidth; + wxStaticText* m_staticLineWidthUnits; + wxStaticText* m_staticText52; + wxSpinCtrl* m_spinPinLength; + wxStaticText* m_staticPinLengthUnits; + wxStaticText* m_staticText7; + wxSpinCtrl* m_spinPinNumSize; + wxStaticText* m_staticTextSizeUnits; + wxStaticText* m_staticText9; + wxSpinCtrl* m_spinPinNameSize; + wxStaticText* m_staticRepeatXUnits; + wxStaticText* m_staticText11; + wxSpinCtrl* m_spinRepeatHorizontal; + wxStaticText* m_staticText12; + wxStaticText* m_staticText13; + wxSpinCtrl* m_spinRepeatVertical; + wxStaticText* m_staticText14; + wxStaticText* m_staticText15; + wxChoice* m_choicePinDisplacement; + wxStaticText* m_staticText16; + wxStaticText* m_staticText17; + wxSpinCtrl* m_spinRepeatLabel; + wxStaticText* m_stMaxUndoItems; + wxSpinCtrl* m_spinMaxUndoItems; + wxStaticText* m_stMaxUndoItemsUnit; + wxStaticLine* m_staticline3; + wxCheckBox* m_checkShowGrid; + wxStaticLine* m_staticline2; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + public: + + DIALOG_LIBEDIT_OPTIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Library Editor Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 487,433 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_LIBEDIT_OPTIONS_BASE(); + +}; + +#endif //__DIALOG_LIBEDIT_OPTIONS_BASE_H__ diff --git a/eeschema/dialogs/dialog_netlist.cpp b/eeschema/dialogs/dialog_netlist.cpp new file mode 100644 index 00000000..bd42d3dd --- /dev/null +++ b/eeschema/dialogs/dialog_netlist.cpp @@ -0,0 +1,886 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013-2015 Jean-Pierre Charras, jp.charras@wanadoo.fr + * Copyright (C) 2013-2015 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file eeschema/dialogs/dialog_netlist.cpp + * @brief Dialog box for creating netlists. + */ + +/* Functions relative to the dialog creating the netlist for Pcbnew. + * The dialog is a notebook with 4 fixed netlist format: + * Pcbnew ORCADPCB2 CADSTAR and SPICE + * and up to CUSTOMPANEL_COUNTMAX (see netlist.h) user programmable format + * calling an external converter with convert an intermediate format to the + * user specific format. + * these external converters are referred there as plugins, + * but there are not really plugins, there are only external binaries + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins + + +/* panel (notebook page) identifiers */ +enum panel_netlist_index { + PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */ + PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */ + PANELCADSTAR, /* Handle Netlist format CadStar */ + PANELSPICE, /* Handle Netlist format Pspice */ + PANELCUSTOMBASE /* First auxiliary panel (custom netlists). + * others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */ +}; + + +/* wxPanels for creating the NoteBook pages for each netlist format: */ +class NETLIST_PAGE_DIALOG : public wxPanel +{ +public: + NETLIST_TYPE_ID m_IdNetType; + wxCheckBox* m_IsCurrentFormat; + wxCheckBox* m_AddSubPrefix; + wxCheckBox* m_SpiceUseNetcodeAsNetname; + wxTextCtrl* m_CommandStringCtrl; + wxTextCtrl* m_TitleStringCtrl; + wxButton* m_ButtonCancel; + wxBoxSizer* m_LeftBoxSizer; + wxBoxSizer* m_RightBoxSizer; + wxBoxSizer* m_RightOptionsBoxSizer; + wxBoxSizer* m_LowBoxSizer; + +private: + wxString m_pageNetFmtName; + +public: + /** Constructor to create a setup page for one netlist format. + * Used in Netlist format Dialog box creation + * @param parent = wxNotebook * parent + * @param title = title (name) of the notebook page + * @param id_NetType = netlist type id + */ + NETLIST_PAGE_DIALOG( wxNotebook* parent, const wxString& title, + NETLIST_TYPE_ID id_NetType ); + ~NETLIST_PAGE_DIALOG() { }; + + /** + * function GetPageNetFmtName + * @return the name of the netlist format for this page + * This is also the page label. + */ + const wxString GetPageNetFmtName() + { + return m_pageNetFmtName; + } +}; + + +/* Dialog frame for creating netlists */ +class NETLIST_DIALOG : public NETLIST_DIALOG_BASE +{ +public: + SCH_EDIT_FRAME* m_Parent; + wxString m_NetFmtName; + NETLIST_PAGE_DIALOG* m_PanelNetType[4 + CUSTOMPANEL_COUNTMAX]; + +private: + wxConfigBase* m_config; + +public: + + // Constructor and destructor + NETLIST_DIALOG( SCH_EDIT_FRAME* parent ); + ~NETLIST_DIALOG() { }; + +private: + void InstallCustomPages(); + NETLIST_PAGE_DIALOG* AddOneCustomPage( const wxString & aTitle, + const wxString & aCommandString, + NETLIST_TYPE_ID aNetTypeId ); + void InstallPageSpice(); + void GenNetlist( wxCommandEvent& event ); + void RunSimulator( wxCommandEvent& event ); + void NetlistUpdateOpt(); + void OnCancelClick( wxCommandEvent& event ); + void OnNetlistTypeSelection( wxNotebookEvent& event ); + void SelectDefaultNetlistType( wxCommandEvent& event ); + + /** + * Function OnAddPlugin + * Add a new panel for a new netlist plugin + */ + void OnAddPlugin( wxCommandEvent& event ); + + /** + * Function OnDelPlugin + * Remove a panel relative to a netlist plugin + */ + void OnDelPlugin( wxCommandEvent& event ); + + /** + * Function WriteCurrentNetlistSetup + * Write the current netlist options setup in the configuration + */ + void WriteCurrentNetlistSetup(); + + bool GetUseDefaultNetlistName() + { + return m_cbUseDefaultNetlistName->IsChecked(); + } + + /** + * Function UserNetlistTypeName + * to retrieve user netlist type names + * @param first_item = true: return first name of the list, false = return next + * @return a wxString : name of the type netlist or empty string + * this function must be called first with "first_item" = true + * and after with "first_item" = false to get all the other existing netlist names + */ + const wxString UserNetlistTypeName( bool first_item ); + + /** + * Function FilenamePrms + * returns the filename extension and the wildcard string for this curr + * or a void name if there is no default name + * @param aNetTypeId = the netlist type ( NET_TYPE_PCBNEW ... ) + * @param aExt = a reference to a wxString to return the default file ext. + * @param aWildCard = reference to a wxString to return the default wildcard. + * @return true for known netlist type, false for custom formats + */ + bool FilenamePrms( NETLIST_TYPE_ID aNetTypeId, + wxString * aExt, wxString * aWildCard ); + + DECLARE_EVENT_TABLE() +}; + + +class NETLIST_DIALOG_ADD_PLUGIN : public NETLIST_DIALOG_ADD_PLUGIN_BASE +{ +private: + NETLIST_DIALOG* m_Parent; + +public: + NETLIST_DIALOG_ADD_PLUGIN( NETLIST_DIALOG* parent ); + const wxString GetPluginTitle() + { + return m_textCtrlName->GetValue(); + } + const wxString GetPluginTCommandLine() + { + return m_textCtrlCommand->GetValue(); + } + +private: + + /** + * Function OnOKClick + * Validate info relative to a new netlist plugin + */ + void OnOKClick( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); + + /* + * Browse plugin files, and set m_CommandStringCtrl field + */ + void OnBrowsePlugins( wxCommandEvent& event ); +}; + + +/* Event id for notebook page buttons: */ +enum id_netlist { + ID_CREATE_NETLIST = ID_END_EESCHEMA_ID_LIST + 1, + ID_CURRENT_FORMAT_IS_DEFAULT, + ID_RUN_SIMULATOR, + ID_ADD_SUBCIRCUIT_PREFIX, + ID_USE_NETCODE_AS_NETNAME +}; + + +// ID for configuration: +#define CUSTOM_NETLIST_TITLE wxT( "CustomNetlistTitle" ) +#define CUSTOM_NETLIST_COMMAND wxT( "CustomNetlistCommand" ) +#define NETLIST_USE_DEFAULT_NETNAME wxT( "NetlistUseDefaultNetname" ) +#define NETLIST_PSPICE_USE_NETNAME wxT( "SpiceUseNetNames" ) + + +BEGIN_EVENT_TABLE( NETLIST_DIALOG, NETLIST_DIALOG_BASE ) + EVT_BUTTON( ID_CREATE_NETLIST, NETLIST_DIALOG::GenNetlist ) + EVT_CHECKBOX( ID_CURRENT_FORMAT_IS_DEFAULT, + NETLIST_DIALOG::SelectDefaultNetlistType ) + EVT_BUTTON( ID_RUN_SIMULATOR, NETLIST_DIALOG::RunSimulator ) +END_EVENT_TABLE() + + + +NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent, + const wxString& title, + NETLIST_TYPE_ID id_NetType ) : + wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize, + wxTAB_TRAVERSAL | wxBORDER_SUNKEN ) +{ + m_IdNetType = id_NetType; + m_pageNetFmtName = title; + m_CommandStringCtrl = NULL; + m_TitleStringCtrl = NULL; + m_IsCurrentFormat = NULL; + m_AddSubPrefix = NULL; + m_SpiceUseNetcodeAsNetname = NULL; + m_ButtonCancel = NULL; + + wxString netfmtName = ((NETLIST_DIALOG*)parent->GetParent())->m_NetFmtName; + + bool selected = m_pageNetFmtName == netfmtName; + + // PCBNEW Format is a special type: + if( id_NetType == NET_TYPE_PCBNEW ) + { + selected = true; + } + + + parent->AddPage( this, title, selected ); + + wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL ); + SetSizer( MainBoxSizer ); + wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + m_LowBoxSizer = new wxBoxSizer( wxVERTICAL ); + MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 ); + MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 ); + + m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL ); + m_RightBoxSizer = new wxBoxSizer( wxVERTICAL ); + m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL ); + UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 ); + UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 ); + UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 ); + + wxStaticText* text = new wxStaticText( this, -1, _( "Options:" ) ); + m_LeftBoxSizer->Add( text, 0, wxGROW | wxALL, 5 ); + + m_IsCurrentFormat = new wxCheckBox( this, ID_CURRENT_FORMAT_IS_DEFAULT, + _( "Default format" ) ); + m_LeftBoxSizer->Add( m_IsCurrentFormat, 0, wxGROW | wxALL, 5 ); + m_IsCurrentFormat->SetValue( selected ); +} + + + +NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) : + NETLIST_DIALOG_BASE( parent ) +{ + m_Parent = parent; + m_config = Kiface().KifaceSettings(); + + long tmp; + m_config->Read( NETLIST_USE_DEFAULT_NETNAME, &tmp, 0l ); + m_cbUseDefaultNetlistName->SetValue( tmp ); + m_NetFmtName = m_Parent->GetNetListFormatName(); + + for( int ii = 0; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ii++ ) + { + m_PanelNetType[ii] = NULL; + } + + // Add notebook pages: + + // Add Panel FORMAT PCBNEW + m_PanelNetType[PANELPCBNEW] = + new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Pcbnew" ), + NET_TYPE_PCBNEW ); + + // Add Panel FORMAT ORCADPCB2 + m_PanelNetType[PANELORCADPCB2] = + new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "OrcadPCB2" ), + NET_TYPE_ORCADPCB2 ); + + // Add Panel FORMAT CADSTAR + m_PanelNetType[PANELCADSTAR] = + new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ), + NET_TYPE_CADSTAR ); + + // Add Panel spice + InstallPageSpice(); + + // Add custom panels: + InstallCustomPages(); + + SetDefaultItem( m_buttonNetlist ); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +const wxString NETLIST_DIALOG::UserNetlistTypeName( bool first_item ) +{ + static int index; + wxString name, msg; + + if( first_item ) + index = 0; + else + index++; + + msg = CUSTOM_NETLIST_TITLE; + msg << index + 1; + + name = m_config->Read( msg ); + + return name; +} + + +void NETLIST_DIALOG::InstallPageSpice() +{ + wxButton* Button; + NETLIST_PAGE_DIALOG* page; + wxString title = wxT( "Spice" ); + + page = m_PanelNetType[PANELSPICE] = + new NETLIST_PAGE_DIALOG( m_NoteBook, title, NET_TYPE_SPICE ); + + page->m_AddSubPrefix = new wxCheckBox( page, ID_ADD_SUBCIRCUIT_PREFIX, + _( "Prefix references 'U' and 'IC' with 'X'" ) ); + page->m_AddSubPrefix->SetValue( m_Parent->GetSpiceAddReferencePrefix() ); + page->m_LeftBoxSizer->Add( page->m_AddSubPrefix, 0, wxGROW | wxALL, 5 ); + + page->m_SpiceUseNetcodeAsNetname = new wxCheckBox( page, ID_USE_NETCODE_AS_NETNAME, + _( "Use net number as net name" ) ); + page->m_SpiceUseNetcodeAsNetname->SetValue( m_Parent->GetSpiceUseNetcodeAsNetname() ); + page->m_LeftBoxSizer->Add( page->m_SpiceUseNetcodeAsNetname, 0, wxGROW | wxALL, 5 ); + + page->m_LowBoxSizer->Add( new wxStaticText( page, -1, _( "Simulator command:" ) ), 0, + wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 ); + + page->m_CommandStringCtrl = new wxTextCtrl( page, -1, m_Parent->GetSimulatorCommand(), + wxDefaultPosition, wxDefaultSize ); + + page->m_CommandStringCtrl->SetInsertionPoint( 1 ); + page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, + 0, + wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, + 5 ); + + // Add buttons + Button = new wxButton( page, ID_RUN_SIMULATOR, _( "&Run Simulator" ) ); + page->m_RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); +} + + +void NETLIST_DIALOG::InstallCustomPages() +{ + int ii; + wxString title, msg; + NETLIST_PAGE_DIALOG* currPage; + + for( ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ ) + { + title = UserNetlistTypeName( ii == 0 ? true : false ); + + if( title.IsEmpty() ) + break; // No more panel to install + + // Install a plugin panel + msg = CUSTOM_NETLIST_COMMAND; + msg << ii + 1; + wxString command = m_config->Read( msg ); + + currPage = AddOneCustomPage( title, command, + (NETLIST_TYPE_ID)(NET_TYPE_CUSTOM1 + ii) ); + m_PanelNetType[PANELCUSTOMBASE + ii] = currPage; + } +} + + +NETLIST_PAGE_DIALOG* NETLIST_DIALOG::AddOneCustomPage( const wxString & aTitle, + const wxString & aCommandString, + NETLIST_TYPE_ID aNetTypeId ) +{ + NETLIST_PAGE_DIALOG* currPage; + + currPage = new NETLIST_PAGE_DIALOG( m_NoteBook, aTitle, aNetTypeId ); + + + currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, + -1, _( "Netlist command:" ) ), 0, + wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 ); + + currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString, + wxDefaultPosition, wxDefaultSize ); + + currPage->m_CommandStringCtrl->SetInsertionPoint( 1 ); + currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, + 0, + wxGROW | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, + 5 ); + + currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, + -1, _( "Title:" ) ), 0, + wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 ); + + currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle, + wxDefaultPosition, wxDefaultSize ); + + currPage->m_TitleStringCtrl->SetInsertionPoint( 1 ); + currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, + 0, + wxGROW | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, + 5 ); + return currPage; +} + + +void NETLIST_DIALOG::SelectDefaultNetlistType( wxCommandEvent& event ) +{ + int ii; + NETLIST_PAGE_DIALOG* currPage; + + for( ii = 0; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ii++ ) + if( m_PanelNetType[ii] ) + m_PanelNetType[ii]->m_IsCurrentFormat->SetValue( false ); + + currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage(); + + if( currPage == NULL ) + return; + + m_Parent->SetNetListFormatName( currPage->GetPageNetFmtName() ); + currPage->m_IsCurrentFormat->SetValue( true ); +} + + +void NETLIST_DIALOG::OnNetlistTypeSelection( wxNotebookEvent& event ) +{ + NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage(); + if( currPage == NULL ) + return; + + m_buttonDelPlugin->Enable( currPage->m_IdNetType >= NET_TYPE_CUSTOM1 ); + m_cbUseDefaultNetlistName->Enable( currPage->m_IdNetType < NET_TYPE_CUSTOM1 ); + + wxString fileExt; + if( FilenamePrms( currPage->m_IdNetType, &fileExt, NULL ) ) + { + wxFileName fn = g_RootSheet->GetScreen()->GetFileName(); + fn.SetExt( fileExt ); + m_textCtrlDefaultFileName->SetValue( fn.GetFullName() ); + } + else + m_textCtrlDefaultFileName->Clear(); +} + + +void NETLIST_DIALOG::NetlistUpdateOpt() +{ + int ii; + + m_Parent->SetSpiceAddReferencePrefix( m_PanelNetType[PANELSPICE]->m_AddSubPrefix->IsChecked() ); + m_Parent->SetSpiceUseNetcodeAsNetname( m_PanelNetType[PANELSPICE]->m_SpiceUseNetcodeAsNetname->IsChecked() ); + m_Parent->SetSimulatorCommand( m_PanelNetType[PANELSPICE]->m_CommandStringCtrl->GetValue() ); + m_Parent->SetNetListFormatName( wxEmptyString ); + + for( ii = 0; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ii++ ) + { + if( m_PanelNetType[ii] == NULL ) + break; + + if( m_PanelNetType[ii]->m_IsCurrentFormat->GetValue() == true ) + m_Parent->SetNetListFormatName( m_PanelNetType[ii]->GetPageNetFmtName() ); + } +} + + +void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event ) +{ + wxFileName fn; + wxString fileWildcard; + wxString fileExt; + wxString title = _( "Save Netlist File" ); + + NetlistUpdateOpt(); + + NETLIST_PAGE_DIALOG* currPage; + currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage(); + + unsigned netlist_opt = 0; + + // Calculate the netlist filename + fn = g_RootSheet->GetScreen()->GetFileName(); + FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard ); + + // Set some parameters + switch( currPage->m_IdNetType ) + { + case NET_TYPE_SPICE: + // Set spice netlist options: + if( currPage->m_AddSubPrefix->GetValue() ) + netlist_opt |= NET_USE_X_PREFIX; + + if( currPage->m_SpiceUseNetcodeAsNetname->GetValue() ) + netlist_opt |= NET_USE_NETCODES_AS_NETNAMES; + break; + + case NET_TYPE_CADSTAR: + break; + + case NET_TYPE_PCBNEW: + break; + + case NET_TYPE_ORCADPCB2: + break; + + default: // custom, NET_TYPE_CUSTOM1 and greater + title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue().GetData() ); + } + + fn.SetExt( fileExt ); + + if( fn.GetPath().IsEmpty() ) + fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) ); + + wxString fullpath = fn.GetFullPath(); + + if( !GetUseDefaultNetlistName() || currPage->m_IdNetType >= NET_TYPE_CUSTOM1 ) + { + wxString fullname = fn.GetFullName(); + wxString path = fn.GetPath(); + + // fullname does not and should not include the path, per wx docs. + wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + fullpath = dlg.GetPath(); // directory + filename + } + + m_Parent->ClearMsgPanel(); + + if( currPage->m_CommandStringCtrl ) + m_Parent->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() ); + else + m_Parent->SetNetListerCommand( wxEmptyString ); + + m_Parent->CreateNetlist( currPage->m_IdNetType, fullpath, netlist_opt ); + + WriteCurrentNetlistSetup(); + + EndModal( wxID_OK ); +} + + +bool NETLIST_DIALOG::FilenamePrms( NETLIST_TYPE_ID aNetTypeId, + wxString * aExt, wxString * aWildCard ) +{ + wxString fileExt; + wxString fileWildcard; + + bool ret = true; + + switch( aNetTypeId ) + { + case NET_TYPE_SPICE: + fileExt = wxT( "cir" ); + fileWildcard = _( "SPICE netlist file (.cir)|*.cir" ); + break; + + case NET_TYPE_CADSTAR: + fileExt = wxT( "frp" ); + fileWildcard = _( "CadStar netlist file (.frp)|*.frp" ); + break; + + case NET_TYPE_PCBNEW: + case NET_TYPE_ORCADPCB2: + fileExt = NetlistFileExtension; + fileWildcard = NetlistFileWildcard; + break; + + default: // custom, NET_TYPE_CUSTOM1 and greater + fileWildcard = AllFilesWildcard; + ret = false; + } + + if( aExt ) + *aExt = fileExt; + + if( aWildCard ) + *aWildCard = fileWildcard; + + return ret; +} + + +void NETLIST_DIALOG::OnCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +void NETLIST_DIALOG::RunSimulator( wxCommandEvent& event ) +{ + wxFileName fn; + wxString ExecFile, CommandLine; + + NetlistUpdateOpt(); + + wxString tmp = m_PanelNetType[PANELSPICE]->m_CommandStringCtrl->GetValue(); + tmp.Trim( false ); + tmp.Trim( true ); + m_Parent->SetSimulatorCommand( tmp ); + ExecFile = tmp.BeforeFirst( ' ' ); + CommandLine = tmp.AfterFirst( ' ' ); + + // Calculate the netlist filename + fn = g_RootSheet->GetScreen()->GetFileName(); + fn.SetExt( wxT( "cir" ) ); + CommandLine += wxT( " \"" ) + fn.GetFullPath() + wxT( "\"" ); + + NETLIST_PAGE_DIALOG* currPage; + currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage(); + + // Set spice netlist options: + unsigned netlist_opt = 0; + + if( currPage->m_AddSubPrefix && currPage->m_AddSubPrefix->GetValue() ) + netlist_opt |= NET_USE_X_PREFIX; + + if( currPage->m_SpiceUseNetcodeAsNetname && currPage->m_SpiceUseNetcodeAsNetname->GetValue() ) + netlist_opt |= NET_USE_NETCODES_AS_NETNAMES; + + if( ! m_Parent->CreateNetlist( currPage->m_IdNetType, fn.GetFullPath(), + netlist_opt ) ) + return; + + ExecuteFile( this, ExecFile, CommandLine ); +} + + +void NETLIST_DIALOG::WriteCurrentNetlistSetup() +{ + wxString msg, Command; + + NetlistUpdateOpt(); + + m_config->Write( NETLIST_USE_DEFAULT_NETNAME, GetUseDefaultNetlistName() ); + + // Update existing custom pages + int jj = 0; + for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ ) + { + NETLIST_PAGE_DIALOG* currPage = m_PanelNetType[ii + PANELCUSTOMBASE]; + + if( currPage == NULL ) + break; + + wxString title = currPage->m_TitleStringCtrl->GetValue(); + + if( title.IsEmpty() ) + continue; + + msg = CUSTOM_NETLIST_TITLE; + msg << jj + 1; + m_config->Write( msg, title ); + + Command = currPage->m_CommandStringCtrl->GetValue(); + msg = CUSTOM_NETLIST_COMMAND; + msg << jj + 1; + m_config->Write( msg, Command ); + jj++; + } + + // Ensure all other pages are void + for(; jj < CUSTOMPANEL_COUNTMAX; jj++ ) + { + msg = CUSTOM_NETLIST_TITLE; + msg << jj + 1; + m_config->Write( msg, wxEmptyString ); + + msg = CUSTOM_NETLIST_COMMAND; + msg << jj + 1; + m_config->Write( msg, wxEmptyString ); + } +} + + +void NETLIST_DIALOG::OnDelPlugin( wxCommandEvent& event ) +{ + NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage(); + + currPage->m_CommandStringCtrl->SetValue( wxEmptyString ); + currPage->m_TitleStringCtrl->SetValue( wxEmptyString ); + + if( currPage->m_IsCurrentFormat->IsChecked() ) + { + currPage->m_IsCurrentFormat->SetValue( false ); + m_PanelNetType[PANELPCBNEW]->m_IsCurrentFormat->SetValue( true ); + } + + WriteCurrentNetlistSetup(); + EndModal( NET_PLUGIN_CHANGE ); +} + + +void NETLIST_DIALOG::OnAddPlugin( wxCommandEvent& event ) +{ + NETLIST_DIALOG_ADD_PLUGIN dlg( this ); + if( dlg.ShowModal() != wxID_OK ) + return; + + // Creates a new custom plugin page + wxString title = dlg.GetPluginTitle(); + + // Verify it does not exists + int netTypeId = PANELCUSTOMBASE; // the first not used type id + NETLIST_PAGE_DIALOG* currPage; + for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ ) + { + netTypeId = PANELCUSTOMBASE + ii; + currPage = m_PanelNetType[ii + PANELCUSTOMBASE]; + + if( currPage == NULL ) + break; + + if( currPage->GetPageNetFmtName() == title ) + { + wxMessageBox( _("This plugin already exists. Abort") ); + return; + } + } + + wxString cmd = dlg.GetPluginTCommandLine(); + currPage = AddOneCustomPage( title,cmd, (NETLIST_TYPE_ID)netTypeId ); + m_PanelNetType[netTypeId] = currPage; + WriteCurrentNetlistSetup(); + + // Close and reopen dialog to rebuild the dialog after changes + EndModal( NET_PLUGIN_CHANGE ); +} + + +NETLIST_DIALOG_ADD_PLUGIN::NETLIST_DIALOG_ADD_PLUGIN( NETLIST_DIALOG* parent ) : + NETLIST_DIALOG_ADD_PLUGIN_BASE( parent ) +{ + m_Parent = parent; + GetSizer()->SetSizeHints( this ); +} + + +void NETLIST_DIALOG_ADD_PLUGIN::OnOKClick( wxCommandEvent& event ) +{ + if( m_textCtrlCommand->GetValue() == wxEmptyString ) + { + wxMessageBox( _( "Error. You must provide a command String" ) ); + return; + } + + if( m_textCtrlName->GetValue() == wxEmptyString ) + { + wxMessageBox( _( "Error. You must provide a Title" ) ); + return; + } + + EndModal( wxID_OK ); +} + + +void NETLIST_DIALOG_ADD_PLUGIN::OnCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +void NETLIST_DIALOG_ADD_PLUGIN::OnBrowsePlugins( wxCommandEvent& event ) +{ + wxString FullFileName, Mask, Path; + + Mask = wxT( "*" ); +#ifndef __WXMAC__ + Path = Pgm().GetExecutablePath(); +#else + Path = GetOSXKicadDataDir() + wxT( "/plugins" ); +#endif + FullFileName = EDA_FILE_SELECTOR( _( "Plugin files:" ), + Path, + FullFileName, + wxEmptyString, + Mask, + this, + wxFD_OPEN, + true + ); + if( FullFileName.IsEmpty() ) + return; + + // Creates a default command line, suitable for external tool xslproc or python + // try to build a default command line depending on plugin extension + // "xsl" or "exe" or "py" + wxString cmdLine; + wxFileName fn( FullFileName ); + wxString ext = fn.GetExt(); + + if( ext == wxT("xsl" ) ) + cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars(FullFileName) ); + else if( ext == wxT("exe" ) || ext.IsEmpty() ) + cmdLine.Printf(wxT("\"%s\" > \"%%O\" < \"%%I\""), GetChars(FullFileName) ); + else if( ext == wxT("py" ) || ext.IsEmpty() ) + cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars(FullFileName) ); + else + cmdLine.Printf(wxT("\"%s\""), GetChars(FullFileName) ); + + m_textCtrlCommand->SetValue( cmdLine ); + + /* Get a title for this page */ + wxString title = m_textCtrlName->GetValue(); + + if( title.IsEmpty() ) + wxMessageBox( _( "Do not forget to choose a title for this netlist control page" ) ); +} + + +int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller ) +{ + NETLIST_DIALOG dlg( aCaller ); + + return dlg.ShowModal(); +} + diff --git a/eeschema/dialogs/dialog_netlist_base.cpp b/eeschema/dialogs/dialog_netlist_base.cpp new file mode 100644 index 00000000..39a8d0de --- /dev/null +++ b/eeschema/dialogs/dialog_netlist_base.cpp @@ -0,0 +1,151 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_netlist_base.h" + +/////////////////////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE( NETLIST_DIALOG_BASE, DIALOG_SHIM ) + EVT_NOTEBOOK_PAGE_CHANGED( ID_CHANGE_NOTEBOOK_PAGE, NETLIST_DIALOG_BASE::_wxFB_OnNetlistTypeSelection ) + EVT_BUTTON( ID_CREATE_NETLIST, NETLIST_DIALOG_BASE::_wxFB_GenNetlist ) + EVT_BUTTON( wxID_CANCEL, NETLIST_DIALOG_BASE::_wxFB_OnCancelClick ) + EVT_BUTTON( ID_ADD_PLUGIN, NETLIST_DIALOG_BASE::_wxFB_OnAddPlugin ) + EVT_BUTTON( ID_DEL_PLUGIN, NETLIST_DIALOG_BASE::_wxFB_OnDelPlugin ) +END_EVENT_TABLE() + +NETLIST_DIALOG_BASE::NETLIST_DIALOG_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bUpperSizer; + bUpperSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bRightSizer; + bRightSizer = new wxBoxSizer( wxVERTICAL ); + + m_NoteBook = new wxNotebook( this, ID_CHANGE_NOTEBOOK_PAGE, wxDefaultPosition, wxDefaultSize, 0 ); + + bRightSizer->Add( m_NoteBook, 1, wxEXPAND | wxALL, 5 ); + + + bUpperSizer->Add( bRightSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* bLeftSizer; + bLeftSizer = new wxBoxSizer( wxVERTICAL ); + + + bLeftSizer->Add( 0, 0, 0, wxTOP, 15 ); + + m_buttonNetlist = new wxButton( this, ID_CREATE_NETLIST, _("Generate"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftSizer->Add( m_buttonNetlist, 0, wxALL|wxEXPAND, 5 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftSizer->Add( m_buttonCancel, 0, wxALL|wxEXPAND, 5 ); + + m_buttonAddPlugin = new wxButton( this, ID_ADD_PLUGIN, _("Add Plugin"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftSizer->Add( m_buttonAddPlugin, 0, wxALL|wxEXPAND, 5 ); + + m_buttonDelPlugin = new wxButton( this, ID_DEL_PLUGIN, _("Remove Plugin"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftSizer->Add( m_buttonDelPlugin, 0, wxALL|wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bLeftSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_cbUseDefaultNetlistName = new wxCheckBox( this, wxID_ANY, _("Use default netname"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftSizer->Add( m_cbUseDefaultNetlistName, 0, wxALL, 5 ); + + + bUpperSizer->Add( bLeftSizer, 0, wxEXPAND, 5 ); + + + bMainSizer->Add( bUpperSizer, 1, wxEXPAND, 5 ); + + m_staticTextDefaultFN = new wxStaticText( this, wxID_ANY, _("Default Netlist Filename:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDefaultFN->Wrap( -1 ); + bMainSizer->Add( m_staticTextDefaultFN, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_textCtrlDefaultFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + m_textCtrlDefaultFileName->SetMaxLength( 0 ); + bMainSizer->Add( m_textCtrlDefaultFileName, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +NETLIST_DIALOG_BASE::~NETLIST_DIALOG_BASE() +{ +} + +BEGIN_EVENT_TABLE( NETLIST_DIALOG_ADD_PLUGIN_BASE, DIALOG_SHIM ) + EVT_BUTTON( wxID_OK, NETLIST_DIALOG_ADD_PLUGIN_BASE::_wxFB_OnOKClick ) + EVT_BUTTON( wxID_CANCEL, NETLIST_DIALOG_ADD_PLUGIN_BASE::_wxFB_OnCancelClick ) + EVT_BUTTON( wxID_BROWSE_PLUGINS, NETLIST_DIALOG_ADD_PLUGIN_BASE::_wxFB_OnBrowsePlugins ) +END_EVENT_TABLE() + +NETLIST_DIALOG_ADD_PLUGIN_BASE::NETLIST_DIALOG_ADD_PLUGIN_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizerLeft; + bSizerLeft = new wxBoxSizer( wxVERTICAL ); + + m_staticTextCmd = new wxStaticText( this, wxID_ANY, _("Netlist command:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCmd->Wrap( -1 ); + bSizerLeft->Add( m_staticTextCmd, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_textCtrlCommand = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlCommand->SetMaxLength( 0 ); + m_textCtrlCommand->SetMinSize( wxSize( 300,-1 ) ); + + bSizerLeft->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextName = new wxStaticText( this, wxID_ANY, _("Name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextName->Wrap( -1 ); + bSizerLeft->Add( m_staticTextName, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_textCtrlName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlName->SetMaxLength( 0 ); + bSizerLeft->Add( m_textCtrlName, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizerMain->Add( bSizerLeft, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizerRight; + bSizerRight = new wxBoxSizer( wxVERTICAL ); + + m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonOK->SetDefault(); + bSizerRight->Add( m_buttonOK, 0, wxALL|wxEXPAND, 5 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerRight->Add( m_buttonCancel, 0, wxALL|wxEXPAND, 5 ); + + m_buttonPlugin = new wxButton( this, wxID_BROWSE_PLUGINS, _("Browse Plugins"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerRight->Add( m_buttonPlugin, 0, wxALL|wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerRight, 0, wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +NETLIST_DIALOG_ADD_PLUGIN_BASE::~NETLIST_DIALOG_ADD_PLUGIN_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_netlist_base.fbp b/eeschema/dialogs/dialog_netlist_base.fbp new file mode 100644 index 00000000..c435a739 --- /dev/null +++ b/eeschema/dialogs/dialog_netlist_base.fbp @@ -0,0 +1,1624 @@ + + + + + + C++ + 0 + source_name + 0 + 0 + res + UTF-8 + table + dialog_netlist_base + 1000 + none + 1 + dialog_netlist_base + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + NETLIST_DIALOG_BASE + + 404,334 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Netlist + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bUpperSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bRightSizer + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CHANGE_NOTEBOOK_PAGE + + 0 + + + 0 + + 1 + m_NoteBook + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + OnNetlistTypeSelection + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bLeftSizer + wxVERTICAL + none + + 15 + wxTOP + 0 + + 0 + protected + 0 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_CREATE_NETLIST + Generate + + 0 + + + 0 + + 1 + m_buttonNetlist + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + GenNetlist + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_ADD_PLUGIN + Add Plugin + + 0 + + + 0 + + 1 + m_buttonAddPlugin + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + ID_DEL_PLUGIN + Remove Plugin + + 0 + + + 0 + + 1 + m_buttonDelPlugin + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnDelPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Use default netname + + 0 + + + 0 + + 1 + m_cbUseDefaultNetlistName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Default Netlist Filename: + + 0 + + + 0 + + 1 + m_staticTextDefaultFN + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrlDefaultFileName + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + NETLIST_DIALOG_ADD_PLUGIN_BASE + + 312,144 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Plugins: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizerLeft + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Netlist command: + + 0 + + + 0 + + 1 + m_staticTextCmd + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + 300,-1 + 1 + m_textCtrlCommand + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Name: + + 0 + + + 0 + + 1 + m_staticTextName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrlName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizerRight + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_OK + OK + + 0 + + + 0 + + 1 + m_buttonOK + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnOKClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_BROWSE_PLUGINS + Browse Plugins + + 0 + + + 0 + + 1 + m_buttonPlugin + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnBrowsePlugins + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_netlist_base.h b/eeschema/dialogs/dialog_netlist_base.h new file mode 100644 index 00000000..6cfeda28 --- /dev/null +++ b/eeschema/dialogs/dialog_netlist_base.h @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_NETLIST_BASE_H__ +#define __DIALOG_NETLIST_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class NETLIST_DIALOG_BASE +/////////////////////////////////////////////////////////////////////////////// +class NETLIST_DIALOG_BASE : public DIALOG_SHIM +{ + DECLARE_EVENT_TABLE() + private: + + // Private event handlers + void _wxFB_OnNetlistTypeSelection( wxNotebookEvent& event ){ OnNetlistTypeSelection( event ); } + void _wxFB_GenNetlist( wxCommandEvent& event ){ GenNetlist( event ); } + void _wxFB_OnCancelClick( wxCommandEvent& event ){ OnCancelClick( event ); } + void _wxFB_OnAddPlugin( wxCommandEvent& event ){ OnAddPlugin( event ); } + void _wxFB_OnDelPlugin( wxCommandEvent& event ){ OnDelPlugin( event ); } + + + protected: + enum + { + ID_CHANGE_NOTEBOOK_PAGE = 1000, + ID_CREATE_NETLIST, + ID_ADD_PLUGIN, + ID_DEL_PLUGIN + }; + + wxNotebook* m_NoteBook; + wxButton* m_buttonNetlist; + wxButton* m_buttonCancel; + wxButton* m_buttonAddPlugin; + wxButton* m_buttonDelPlugin; + wxStaticLine* m_staticline1; + wxCheckBox* m_cbUseDefaultNetlistName; + wxStaticText* m_staticTextDefaultFN; + wxTextCtrl* m_textCtrlDefaultFileName; + + // Virtual event handlers, overide them in your derived class + virtual void OnNetlistTypeSelection( wxNotebookEvent& event ) { event.Skip(); } + virtual void GenNetlist( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddPlugin( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDelPlugin( wxCommandEvent& event ) { event.Skip(); } + + + public: + + NETLIST_DIALOG_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Netlist"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 404,334 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~NETLIST_DIALOG_BASE(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class NETLIST_DIALOG_ADD_PLUGIN_BASE +/////////////////////////////////////////////////////////////////////////////// +class NETLIST_DIALOG_ADD_PLUGIN_BASE : public DIALOG_SHIM +{ + DECLARE_EVENT_TABLE() + private: + + // Private event handlers + void _wxFB_OnOKClick( wxCommandEvent& event ){ OnOKClick( event ); } + void _wxFB_OnCancelClick( wxCommandEvent& event ){ OnCancelClick( event ); } + void _wxFB_OnBrowsePlugins( wxCommandEvent& event ){ OnBrowsePlugins( event ); } + + + protected: + enum + { + wxID_BROWSE_PLUGINS = 1000 + }; + + wxStaticText* m_staticTextCmd; + wxTextCtrl* m_textCtrlCommand; + wxStaticText* m_staticTextName; + wxTextCtrl* m_textCtrlName; + wxButton* m_buttonOK; + wxButton* m_buttonCancel; + wxButton* m_buttonPlugin; + + // Virtual event handlers, overide them in your derived class + virtual void OnOKClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnBrowsePlugins( wxCommandEvent& event ) { event.Skip(); } + + + public: + + NETLIST_DIALOG_ADD_PLUGIN_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Plugins:"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 312,144 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~NETLIST_DIALOG_ADD_PLUGIN_BASE(); + +}; + +#endif //__DIALOG_NETLIST_BASE_H__ diff --git a/eeschema/dialogs/dialog_plot_schematic.cpp b/eeschema/dialogs/dialog_plot_schematic.cpp new file mode 100644 index 00000000..2ddd5db8 --- /dev/null +++ b/eeschema/dialogs/dialog_plot_schematic.cpp @@ -0,0 +1,357 @@ +/** @file dialog_plot_schematic.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2015 Jean-Pierre Charras jp.charras at wanadoo.fr + * Copyright (C) 1992-2010 Lorenzo Marcantonio + * Copyright (C) 2011 Wayne Stambaugh + * + * Copyright (C) 1992-2015 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Keys for configuration +#define PLOT_FORMAT_KEY wxT( "PlotFormat" ) +#define PLOT_MODECOLOR_KEY wxT( "PlotModeColor" ) +#define PLOT_FRAME_REFERENCE_KEY wxT( "PlotFrameRef" ) +#define PLOT_HPGL_ORIGIN_KEY wxT( "PlotHPGLOrg" ) +#define PLOT_HPGL_PAPERSIZE_KEY wxT( "PlotHPGLPaperSize" ) +#define PLOT_HPGL_PEN_SIZE_KEY wxT( "PlotHPGLPenSize" ) + + + +// static members (static to remember last state): +int DIALOG_PLOT_SCHEMATIC::m_pageSizeSelect = PAGE_SIZE_AUTO; + + +void SCH_EDIT_FRAME::PlotSchematic( wxCommandEvent& event ) +{ + DIALOG_PLOT_SCHEMATIC dlg( this ); + + dlg.ShowModal(); + + // save project config if the prj config has changed: + if( dlg.PrjConfigChanged() ) + SaveProjectSettings( true ); +} + + +DIALOG_PLOT_SCHEMATIC::DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent ) : + DIALOG_PLOT_SCHEMATIC_BASE( parent ) +{ + m_parent = parent; + m_configChanged = false; + m_config = Kiface().KifaceSettings(); + + initDlg(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + + +// Initialize the dialog options: +void DIALOG_PLOT_SCHEMATIC::initDlg() +{ + // Set paper size option + m_PaperSizeOption->SetSelection( m_pageSizeSelect ); + + // Set color or B&W plot option + bool tmp; + m_config->Read( PLOT_MODECOLOR_KEY, &tmp, true ); + setModeColor( tmp ); + + // Set plot or not frame reference option + m_config->Read( PLOT_FRAME_REFERENCE_KEY, &tmp, true ); + setPlotFrameRef( tmp ); + + // Set HPGL plot origin to center of paper of left bottom corner + m_config->Read( PLOT_HPGL_ORIGIN_KEY, &tmp, false ); + SetPlotOriginCenter( tmp ); + + m_config->Read( PLOT_HPGL_PAPERSIZE_KEY, &m_HPGLPaperSizeSelect, 0 ); + m_HPGLPaperSizeOption->SetSelection( m_HPGLPaperSizeSelect ); + + // HPGL Pen Size is stored in mm in config + m_config->Read( PLOT_HPGL_PEN_SIZE_KEY, &m_HPGLPenSize, 0.5 ); + m_HPGLPenSize *= IU_PER_MM; + + // Switch to the last save plot format + long plotfmt; + m_config->Read( PLOT_FORMAT_KEY, &plotfmt, 0 ); + + switch( plotfmt ) + { + default: + case PLOT_FORMAT_POST: + m_plotFormatOpt->SetSelection( 0 ); + break; + + case PLOT_FORMAT_PDF: + m_plotFormatOpt->SetSelection( 1 ); + break; + + case PLOT_FORMAT_SVG: + m_plotFormatOpt->SetSelection( 2 ); + break; + + case PLOT_FORMAT_DXF: + m_plotFormatOpt->SetSelection( 3 ); + break; + + case PLOT_FORMAT_HPGL: + m_plotFormatOpt->SetSelection( 4 ); + break; + } + + // Set the default line width (pen width which should be used for + // items that do not have a pen size defined (like frame ref) + AddUnitSymbol( *m_defaultLineWidthTitle, g_UserUnit ); + PutValueInLocalUnits( *m_DefaultLineSizeCtrl, GetDefaultLineThickness() ); + + // Initialize HPGL specific widgets + AddUnitSymbol( *m_penHPLGWidthTitle, g_UserUnit ); + PutValueInLocalUnits( *m_penHPGLWidthCtrl, m_HPGLPenSize ); + m_HPGLPaperSizeOption->SetSelection( m_HPGLPaperSizeSelect ); + + // Plot directory + wxString path = m_parent->GetPlotDirectoryName(); +#ifdef __WINDOWS__ + path.Replace( '/', '\\' ); +#endif + m_outputDirectoryName->SetValue( path ); + + // Hide/show widgets that are not always displayed: + wxCommandEvent cmd_event; + OnPlotFormatSelection( cmd_event ); +} + +/* + * TODO: Copy of DIALOG_PLOT::OnOutputDirectoryBrowseClicked in dialog_plot.cpp, maybe merge to a common method. + */ +void DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) +{ + // Build the absolute path of current output plot directory + // to preselect it when opening the dialog. + wxFileName fn( m_outputDirectoryName->GetValue() ); + wxString path = Prj().AbsolutePath( m_outputDirectoryName->GetValue() ); + + wxDirDialog dirDialog( this, _( "Select Output Directory" ), path ); + + if( dirDialog.ShowModal() == wxID_CANCEL ) + { + return; + } + + wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() ); + + fn = Prj().AbsolutePath( g_RootSheet->GetFileName() ); + wxString defaultPath = fn.GetPathWithSep(); + wxString msg; + msg.Printf( _( "Do you want to use a path relative to\n'%s'" ), + GetChars( defaultPath ) ); + + wxMessageDialog dialog( this, msg, _( "Plot Output Directory" ), + wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT ); + + // relative directory selected + if( dialog.ShowModal() == wxID_YES ) + { + if( !dirName.MakeRelativeTo( defaultPath ) ) + wxMessageBox( _( "Cannot make path relative (target volume different from file volume)!" ), + _( "Plot Output Directory" ), wxOK | wxICON_ERROR ); + } + + m_outputDirectoryName->SetValue( dirName.GetFullPath() ); +} + +PlotFormat DIALOG_PLOT_SCHEMATIC::GetPlotFileFormat() +{ + switch( m_plotFormatOpt->GetSelection() ) + { + default: + case 0: return PLOT_FORMAT_POST; + case 1: return PLOT_FORMAT_PDF; + case 2: return PLOT_FORMAT_SVG; + case 3: return PLOT_FORMAT_DXF; + case 4: return PLOT_FORMAT_HPGL; + } +} + + +void DIALOG_PLOT_SCHEMATIC::OnButtonCancelClick( wxCommandEvent& event ) +{ + EndModal( wxID_CANCEL ); +} + + +void DIALOG_PLOT_SCHEMATIC::getPlotOptions() +{ + m_config->Write( PLOT_MODECOLOR_KEY, getModeColor() ); + m_config->Write( PLOT_FRAME_REFERENCE_KEY, getPlotFrameRef() ); + m_config->Write( PLOT_FORMAT_KEY, (long) GetPlotFileFormat() ); + m_config->Write( PLOT_HPGL_ORIGIN_KEY, GetPlotOriginCenter() ); + m_HPGLPaperSizeSelect = m_HPGLPaperSizeOption->GetSelection(); + m_config->Write( PLOT_HPGL_PAPERSIZE_KEY, m_HPGLPaperSizeSelect ); + // HPGL Pen Size is stored in mm in config + m_config->Write( PLOT_HPGL_PEN_SIZE_KEY, m_HPGLPenSize/IU_PER_MM ); + + m_pageSizeSelect = m_PaperSizeOption->GetSelection(); + SetDefaultLineThickness( ValueFromTextCtrl( *m_DefaultLineSizeCtrl ) ); + + // Plot directory + wxString path = m_outputDirectoryName->GetValue(); + path.Replace( '\\', '/' ); + + if( m_parent->GetPlotDirectoryName() != path ) + m_configChanged = true; + + m_parent->SetPlotDirectoryName( path ); + +} + + +void DIALOG_PLOT_SCHEMATIC::OnPlotFormatSelection( wxCommandEvent& event ) +{ + + switch( GetPlotFileFormat() ) + { + default: + case PLOT_FORMAT_POST: + m_paperOptionsSizer->Hide( m_paperHPGLSizer ); + m_paperOptionsSizer->Show( m_PaperSizeOption ); + m_PaperSizeOption->Enable( true ); + m_DefaultLineSizeCtrl->Enable( true ); + break; + + case PLOT_FORMAT_PDF: + m_paperOptionsSizer->Hide( m_paperHPGLSizer ); + m_paperOptionsSizer->Show(m_PaperSizeOption); + m_PaperSizeOption->Enable( true ); + m_DefaultLineSizeCtrl->Enable( true ); + break; + + case PLOT_FORMAT_SVG: + m_paperOptionsSizer->Hide( m_paperHPGLSizer ); + m_paperOptionsSizer->Show(m_PaperSizeOption); + m_PaperSizeOption->Enable( false ); + m_DefaultLineSizeCtrl->Enable( true ); + break; + + case PLOT_FORMAT_DXF: + m_paperOptionsSizer->Hide( m_paperHPGLSizer ); + m_paperOptionsSizer->Show(m_PaperSizeOption); + m_PaperSizeOption->Enable( false ); + m_DefaultLineSizeCtrl->Enable( false ); + break; + + case PLOT_FORMAT_HPGL: + m_paperOptionsSizer->Show( m_paperHPGLSizer ); + m_paperOptionsSizer->Hide(m_PaperSizeOption); + m_DefaultLineSizeCtrl->Enable( false ); + break; + + } + + GetSizer()->SetSizeHints( this ); +} + + +void DIALOG_PLOT_SCHEMATIC::OnButtonPlotCurrentClick( wxCommandEvent& event ) +{ + PlotSchematic( false ); +} + + +void DIALOG_PLOT_SCHEMATIC::OnButtonPlotAllClick( wxCommandEvent& event ) +{ + PlotSchematic( true ); +} + + +void DIALOG_PLOT_SCHEMATIC::PlotSchematic( bool aPlotAll ) +{ + getPlotOptions(); + + switch( GetPlotFileFormat() ) + { + case PLOT_FORMAT_HPGL: + createHPGLFile( aPlotAll, getPlotFrameRef() ); + break; + + case PLOT_FORMAT_DXF: + CreateDXFFile( aPlotAll, getPlotFrameRef() ); + break; + + case PLOT_FORMAT_PDF: + createPDFFile( aPlotAll, getPlotFrameRef() ); + break; + + case PLOT_FORMAT_SVG: + createSVGFile( aPlotAll, getPlotFrameRef() ); + break; + + case PLOT_FORMAT_POST: + // Fall through. Default to Postscript. + default: + createPSFile( aPlotAll, getPlotFrameRef() ); + break; + + } +} + +wxFileName DIALOG_PLOT_SCHEMATIC::createPlotFileName( wxTextCtrl* aOutputDirectoryName, + wxString& aPlotFileName, + wxString& aExtension, + REPORTER* aReporter ) +{ + wxString outputDirName = aOutputDirectoryName->GetValue(); + wxFileName outputDir = wxFileName::DirName( outputDirName ); + + wxString plotFileName = Prj().AbsolutePath( aPlotFileName + wxT(".") + aExtension); + + if( !EnsureFileDirectoryExists( &outputDir, plotFileName, aReporter ) ) + { + wxString msg; + msg.Printf( _( "Could not write plot files to folder '%s'." ), + GetChars( outputDir.GetPath() ) ); + aReporter->Report( msg, REPORTER::RPT_ERROR ); + } + + wxFileName fn( plotFileName ); + fn.SetPath( outputDir.GetFullPath() ); + return fn; +} diff --git a/eeschema/dialogs/dialog_plot_schematic.h b/eeschema/dialogs/dialog_plot_schematic.h new file mode 100644 index 00000000..69cf6c05 --- /dev/null +++ b/eeschema/dialogs/dialog_plot_schematic.h @@ -0,0 +1,157 @@ +/** @file dialog_plot_schematic.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2014 Jean-Pierre Charras + * + * Copyright (C) 1992-2012 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include + + +enum PageFormatReq { + PAGE_SIZE_AUTO, + PAGE_SIZE_A4, + PAGE_SIZE_A +}; + + +class DIALOG_PLOT_SCHEMATIC : public DIALOG_PLOT_SCHEMATIC_BASE +{ +private: + SCH_EDIT_FRAME* m_parent; + wxConfigBase* m_config; + bool m_configChanged; // true if a project config param has changed + static int m_pageSizeSelect; // Static to keep last option for some format: + // Static to keep last option: + // use default size or force A or A4 size + int m_HPGLPaperSizeSelect; // for HPGL format only: last selected paper size + double m_HPGLPenSize; // for HPGL format only: pen size + +public: + // / Constructors + DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent ); + + bool PrjConfigChanged() { return m_configChanged; } // return true if the prj config was modified + // and therefore should be saved + +private: + void OnPlotFormatSelection( wxCommandEvent& event ); + void OnButtonPlotCurrentClick( wxCommandEvent& event ); + void OnButtonPlotAllClick( wxCommandEvent& event ); + void OnButtonCancelClick( wxCommandEvent& event ); + + void initDlg(); + + // common + void getPlotOptions(); + + bool getModeColor() + { return m_ModeColorOption->GetSelection() == 0; } + + void setModeColor( bool aColor ) + { m_ModeColorOption->SetSelection( aColor ? 0 : 1 ); } + + /** + * Set the m_outputDirectoryName variable to the selected directory from directory dialog. + */ + void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ); + + PlotFormat GetPlotFileFormat(); + + bool getPlotFrameRef() { return m_PlotFrameRefOpt->GetValue(); } + void setPlotFrameRef( bool aPlot) {m_PlotFrameRefOpt->SetValue( aPlot ); } + + void PlotSchematic( bool aPlotAll ); + + // PDF + void createPDFFile( bool aPlotAll, bool aPlotFrameRef ); + void plotOneSheetPDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen, bool aPlotFrameRef); + void setupPlotPagePDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen ); + + /** + * Everything done, close the plot and restore the environment + * @param aPlotter the plotter to close and destroy + * @param aOldsheetpath the stored old sheet path for the current sheet before the plot started + */ + void restoreEnvironment( PDF_PLOTTER* aPlotter, SCH_SHEET_PATH& aOldsheetpath ); + + // DXF + void CreateDXFFile( bool aPlotAll, bool aPlotFrameRef ); + bool PlotOneSheetDXF( const wxString& aFileName, SCH_SCREEN* aScreen, + wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef ); + + // HPGL + bool GetPlotOriginCenter() + { + return m_plotOriginOpt->GetSelection() == 1; + } + + void SetPlotOriginCenter( bool aCenter ) + { + m_plotOriginOpt->SetSelection( aCenter ? 1 : 0 ); + } + + void createHPGLFile( bool aPlotAll, bool aPlotFrameRef ); + void SetHPGLPenWidth(); + bool Plot_1_Page_HPGL( const wxString& aFileName, SCH_SCREEN* aScreen, + const PAGE_INFO& aPageInfo, + wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef ); + + // PS + void createPSFile( bool aPlotAll, bool aPlotFrameRef ); + bool plotOneSheetPS( const wxString& aFileName, SCH_SCREEN* aScreen, + const PAGE_INFO& aPageInfo, + wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef ); + + // SVG + void createSVGFile( bool aPlotAll, bool aPlotFrameRef ); + + /** + * Create a file name with an absolute path name + * @param aOutputDirectoryName the diretory name to plot, + * this can be a relative name of the current project diretory or an absolute directory name. + * @param aPlotFileName the name for the file to plot without a path + * @param aExtension the extension for the file to plot + * @param aReporter a point to a REPORTER object use to show messages (can be NULL) + * @return the created file name + * @throw IO_ERROR on file I/O errors + */ + wxFileName createPlotFileName( wxTextCtrl* aOutputDirectoryName, + wxString& aPlotFileName, + wxString& aExtension, REPORTER* aReporter = NULL ); + +public: + // This function is static because it is called by libedit + // outside a dialog. This is the reason we need aFrame as parameter + static bool plotOneSheetSVG( EDA_DRAW_FRAME* aFrame, const wxString& aFileName, + SCH_SCREEN* aScreen, + bool aPlotBlackAndWhite, bool aPlotFrameRef ); +}; diff --git a/eeschema/dialogs/dialog_plot_schematic_base.cpp b/eeschema/dialogs/dialog_plot_schematic_base.cpp new file mode 100644 index 00000000..ca6467dd --- /dev/null +++ b/eeschema/dialogs/dialog_plot_schematic_base.cpp @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "wx_html_report_panel.h" + +#include "dialog_plot_schematic_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_PLOT_SCHEMATIC_BASE::DIALOG_PLOT_SCHEMATIC_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 ); + + wxBoxSizer* bSizer6; + bSizer6 = new wxBoxSizer( wxVERTICAL ); + + m_staticTextOutputDirectory = new wxStaticText( this, wxID_ANY, _("Output directory:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextOutputDirectory->Wrap( -1 ); + bSizer6->Add( m_staticTextOutputDirectory, 0, wxALL, 5 ); + + wxBoxSizer* bSizer5; + bSizer5 = new wxBoxSizer( wxHORIZONTAL ); + + m_outputDirectoryName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_outputDirectoryName->SetMaxLength( 0 ); + m_outputDirectoryName->SetToolTip( _("Target directory for plot files. Can be absolute or relative to the schematic main file location.") ); + + bSizer5->Add( m_outputDirectoryName, 1, wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_browseButton = new wxButton( this, wxID_ANY, _("Browse..."), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer5->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 ); + + + bSizer6->Add( bSizer5, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bSizer6, 0, wxEXPAND|wxLEFT|wxTOP, 5 ); + + m_optionsSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_paperOptionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Paper Options") ), wxVERTICAL ); + + wxString m_PaperSizeOptionChoices[] = { _("Schematic size"), _("Force size A4"), _("Force size A") }; + int m_PaperSizeOptionNChoices = sizeof( m_PaperSizeOptionChoices ) / sizeof( wxString ); + m_PaperSizeOption = new wxRadioBox( this, wxID_ANY, _("Page Size:"), wxDefaultPosition, wxDefaultSize, m_PaperSizeOptionNChoices, m_PaperSizeOptionChoices, 1, wxRA_SPECIFY_COLS ); + m_PaperSizeOption->SetSelection( 1 ); + m_paperOptionsSizer->Add( m_PaperSizeOption, 0, wxALL|wxEXPAND, 5 ); + + m_paperHPGLSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("HPGL Options") ), wxVERTICAL ); + + m_staticText4 = new wxStaticText( this, wxID_ANY, _("Page Size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + m_paperHPGLSizer->Add( m_staticText4, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxString m_HPGLPaperSizeOptionChoices[] = { _("Schematic size"), _("Page size A4"), _("Page size A3"), _("Page size A2"), _("Page size A1"), _("Page size A0"), _("Page size A"), _("Page size B"), _("Page size C"), _("Page size D"), _("Page size E") }; + int m_HPGLPaperSizeOptionNChoices = sizeof( m_HPGLPaperSizeOptionChoices ) / sizeof( wxString ); + m_HPGLPaperSizeOption = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_HPGLPaperSizeOptionNChoices, m_HPGLPaperSizeOptionChoices, 0 ); + m_HPGLPaperSizeOption->SetSelection( 0 ); + m_paperHPGLSizer->Add( m_HPGLPaperSizeOption, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + wxString m_plotOriginOptChoices[] = { _("Bottom left corner"), _("Center of the page") }; + int m_plotOriginOptNChoices = sizeof( m_plotOriginOptChoices ) / sizeof( wxString ); + m_plotOriginOpt = new wxRadioBox( this, wxID_ANY, _("Origin"), wxDefaultPosition, wxDefaultSize, m_plotOriginOptNChoices, m_plotOriginOptChoices, 1, wxRA_SPECIFY_COLS ); + m_plotOriginOpt->SetSelection( 0 ); + m_paperHPGLSizer->Add( m_plotOriginOpt, 0, wxALL, 5 ); + + m_penHPLGWidthTitle = new wxStaticText( this, wxID_ANY, _("Pen width"), wxDefaultPosition, wxDefaultSize, 0 ); + m_penHPLGWidthTitle->Wrap( -1 ); + m_paperHPGLSizer->Add( m_penHPLGWidthTitle, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_penHPGLWidthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_penHPGLWidthCtrl->SetMaxLength( 0 ); + m_paperHPGLSizer->Add( m_penHPGLWidthCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + + m_paperOptionsSizer->Add( m_paperHPGLSizer, 1, wxEXPAND, 5 ); + + + m_optionsSizer->Add( m_paperOptionsSizer, 0, wxEXPAND, 5 ); + + wxString m_plotFormatOptChoices[] = { _("Postscript"), _("PDF"), _("SVG"), _("DXF"), _("HPGL") }; + int m_plotFormatOptNChoices = sizeof( m_plotFormatOptChoices ) / sizeof( wxString ); + m_plotFormatOpt = new wxRadioBox( this, wxID_ANY, _("Format"), wxDefaultPosition, wxDefaultSize, m_plotFormatOptNChoices, m_plotFormatOptChoices, 1, wxRA_SPECIFY_COLS ); + m_plotFormatOpt->SetSelection( 1 ); + m_optionsSizer->Add( m_plotFormatOpt, 0, wxEXPAND|wxLEFT, 5 ); + + wxStaticBoxSizer* sbSizerPlotFormat; + sbSizerPlotFormat = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("General Options") ), wxVERTICAL ); + + m_defaultLineWidthTitle = new wxStaticText( this, wxID_ANY, _("Default line thickness"), wxDefaultPosition, wxDefaultSize, 0 ); + m_defaultLineWidthTitle->Wrap( -1 ); + sbSizerPlotFormat->Add( m_defaultLineWidthTitle, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_DefaultLineSizeCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_DefaultLineSizeCtrl->SetMaxLength( 0 ); + m_DefaultLineSizeCtrl->SetToolTip( _("Selection of the default pen thickness used to draw items, when their thickness is set to 0.") ); + + sbSizerPlotFormat->Add( m_DefaultLineSizeCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + wxString m_ModeColorOptionChoices[] = { _("Color"), _("Black and white") }; + int m_ModeColorOptionNChoices = sizeof( m_ModeColorOptionChoices ) / sizeof( wxString ); + m_ModeColorOption = new wxRadioBox( this, wxID_ANY, _("Mode"), wxDefaultPosition, wxDefaultSize, m_ModeColorOptionNChoices, m_ModeColorOptionChoices, 1, wxRA_SPECIFY_COLS ); + m_ModeColorOption->SetSelection( 1 ); + m_ModeColorOption->SetToolTip( _("Choose if you want to draw the sheet like it appears on screen,\nor in black and white mode, better to print it when using black and white printers") ); + + sbSizerPlotFormat->Add( m_ModeColorOption, 0, wxALL|wxEXPAND, 5 ); + + m_PlotFrameRefOpt = new wxCheckBox( this, wxID_ANY, _("Plot border and title block"), wxDefaultPosition, wxDefaultSize, 0 ); + m_PlotFrameRefOpt->SetValue(true); + m_PlotFrameRefOpt->SetToolTip( _("Print (or not) the Frame references.") ); + + sbSizerPlotFormat->Add( m_PlotFrameRefOpt, 0, wxALL, 5 ); + + + m_optionsSizer->Add( sbSizerPlotFormat, 0, wxEXPAND|wxLEFT, 5 ); + + m_ButtonsSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonPlotCurrent = new wxButton( this, wxID_PRINT_CURRENT, _("Plot Current Page"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonPlotCurrent->SetDefault(); + m_ButtonsSizer->Add( m_buttonPlotCurrent, 0, wxALL|wxEXPAND, 5 ); + + m_buttonPlotAll = new wxButton( this, wxID_PRINT_ALL, _("Plot All Pages"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonPlotAll->SetDefault(); + m_ButtonsSizer->Add( m_buttonPlotAll, 0, wxALL|wxEXPAND, 5 ); + + m_buttonQuit = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ButtonsSizer->Add( m_buttonQuit, 0, wxALL|wxEXPAND, 5 ); + + + m_optionsSizer->Add( m_ButtonsSizer, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bMainSizer->Add( m_optionsSizer, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 ); + + wxBoxSizer* bSizer4; + bSizer4 = new wxBoxSizer( wxVERTICAL ); + + m_staticText2 = new wxStaticText( this, wxID_ANY, _("Messages:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + bSizer4->Add( m_staticText2, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_MessagesBox = new WX_HTML_REPORT_PANEL( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_MessagesBox->SetMinSize( wxSize( 300,150 ) ); + + bSizer4->Add( m_MessagesBox, 1, wxEXPAND | wxALL, 5 ); + + + bMainSizer->Add( bSizer4, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnCloseWindow ) ); + m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnOutputDirectoryBrowseClicked ), NULL, this ); + m_HPGLPaperSizeOption->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnHPGLPageSelected ), NULL, this ); + m_plotFormatOpt->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnPlotFormatSelection ), NULL, this ); + m_buttonPlotCurrent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonPlotCurrentClick ), NULL, this ); + m_buttonPlotAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonPlotAllClick ), NULL, this ); + m_buttonQuit->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonCancelClick ), NULL, this ); +} + +DIALOG_PLOT_SCHEMATIC_BASE::~DIALOG_PLOT_SCHEMATIC_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnCloseWindow ) ); + m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnOutputDirectoryBrowseClicked ), NULL, this ); + m_HPGLPaperSizeOption->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnHPGLPageSelected ), NULL, this ); + m_plotFormatOpt->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnPlotFormatSelection ), NULL, this ); + m_buttonPlotCurrent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonPlotCurrentClick ), NULL, this ); + m_buttonPlotAll->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonPlotAllClick ), NULL, this ); + m_buttonQuit->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_SCHEMATIC_BASE::OnButtonCancelClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_plot_schematic_base.fbp b/eeschema/dialogs/dialog_plot_schematic_base.fbp new file mode 100644 index 00000000..0018cb26 --- /dev/null +++ b/eeschema/dialogs/dialog_plot_schematic_base.fbp @@ -0,0 +1,1852 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_plot_schematic_base + 1000 + none + 1 + Dialog_plot_schematic_base + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + -1,-1 + DIALOG_PLOT_SCHEMATIC_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Plot Schematic + + + + + + + + + + + + + + OnCloseWindow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxLEFT|wxTOP + 0 + + + bSizer6 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Output directory: + + 0 + + + 0 + + 1 + m_staticTextOutputDirectory + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer5 + wxHORIZONTAL + none + + 5 + wxEXPAND|wxLEFT|wxRIGHT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_outputDirectoryName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Target directory for plot files. Can be absolute or relative to the schematic main file location. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Browse... + + 0 + + + 0 + + 1 + m_browseButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnOutputDirectoryBrowseClicked + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxLEFT|wxRIGHT|wxTOP + 0 + + + m_optionsSizer + wxHORIZONTAL + protected + + 5 + wxEXPAND + 0 + + wxID_ANY + Paper Options + + m_paperOptionsSizer + wxVERTICAL + protected + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Schematic size" "Force size A4" "Force size A" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Page Size: + 1 + + 0 + + + 0 + + 1 + m_PaperSizeOption + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + wxID_ANY + HPGL Options + + m_paperHPGLSizer + wxVERTICAL + protected + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Page Size: + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Schematic size" "Page size A4" "Page size A3" "Page size A2" "Page size A1" "Page size A0" "Page size A" "Page size B" "Page size C" "Page size D" "Page size E" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_HPGLPaperSizeOption + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnHPGLPageSelected + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Bottom left corner" "Center of the page" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Origin + 1 + + 0 + + + 0 + + 1 + m_plotOriginOpt + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pen width + + 0 + + + 0 + + 1 + m_penHPLGWidthTitle + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_penHPGLWidthCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Postscript" "PDF" "SVG" "DXF" "HPGL" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Format + 1 + + 0 + + + 0 + + 1 + m_plotFormatOpt + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + OnPlotFormatSelection + + + + + + + + + + 5 + wxEXPAND|wxLEFT + 0 + + wxID_ANY + General Options + + sbSizerPlotFormat + wxVERTICAL + none + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Default line thickness + + 0 + + + 0 + + 1 + m_defaultLineWidthTitle + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_DefaultLineSizeCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Selection of the default pen thickness used to draw items, when their thickness is set to 0. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Color" "Black and white" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Mode + 1 + + 0 + + + 0 + + 1 + m_ModeColorOption + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + Choose if you want to draw the sheet like it appears on screen, or in black and white mode, better to print it when using black and white printers + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Plot border and title block + + 0 + + + 0 + + 1 + m_PlotFrameRefOpt + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Print (or not) the Frame references. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + m_ButtonsSizer + wxVERTICAL + protected + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_PRINT_CURRENT + Plot Current Page + + 0 + + + 0 + + 1 + m_buttonPlotCurrent + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonPlotCurrentClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_PRINT_ALL + Plot All Pages + + 0 + + + 0 + + 1 + m_buttonPlotAll + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonPlotAllClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Close + + 0 + + + 0 + + 1 + m_buttonQuit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 1 + + + bSizer4 + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Messages: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 300,150 + 1 + m_MessagesBox + 1 + + + protected + 1 + + Resizable + 1 + + WX_HTML_REPORT_PANEL; wx_html_report_panel.h + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_plot_schematic_base.h b/eeschema/dialogs/dialog_plot_schematic_base.h new file mode 100644 index 00000000..b983cca9 --- /dev/null +++ b/eeschema/dialogs/dialog_plot_schematic_base.h @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_PLOT_SCHEMATIC_BASE_H__ +#define __DIALOG_PLOT_SCHEMATIC_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; +class WX_HTML_REPORT_PANEL; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_PLOT_SCHEMATIC_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_PLOT_SCHEMATIC_BASE : public DIALOG_SHIM +{ + private: + + protected: + enum + { + wxID_PRINT_CURRENT = 1000, + wxID_PRINT_ALL + }; + + wxStaticText* m_staticTextOutputDirectory; + wxTextCtrl* m_outputDirectoryName; + wxButton* m_browseButton; + wxBoxSizer* m_optionsSizer; + wxStaticBoxSizer* m_paperOptionsSizer; + wxRadioBox* m_PaperSizeOption; + wxStaticBoxSizer* m_paperHPGLSizer; + wxStaticText* m_staticText4; + wxChoice* m_HPGLPaperSizeOption; + wxRadioBox* m_plotOriginOpt; + wxStaticText* m_penHPLGWidthTitle; + wxTextCtrl* m_penHPGLWidthCtrl; + wxRadioBox* m_plotFormatOpt; + wxStaticText* m_defaultLineWidthTitle; + wxTextCtrl* m_DefaultLineSizeCtrl; + wxRadioBox* m_ModeColorOption; + wxCheckBox* m_PlotFrameRefOpt; + wxBoxSizer* m_ButtonsSizer; + wxButton* m_buttonPlotCurrent; + wxButton* m_buttonPlotAll; + wxButton* m_buttonQuit; + wxStaticText* m_staticText2; + WX_HTML_REPORT_PANEL* m_MessagesBox; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseWindow( wxCloseEvent& event ) { event.Skip(); } + virtual void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) { event.Skip(); } + virtual void OnHPGLPageSelected( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPlotFormatSelection( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonPlotCurrentClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonPlotAllClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonCancelClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_PLOT_SCHEMATIC_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Plot Schematic"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_PLOT_SCHEMATIC_BASE(); + +}; + +#endif //__DIALOG_PLOT_SCHEMATIC_BASE_H__ diff --git a/eeschema/dialogs/dialog_print_using_printer.cpp b/eeschema/dialogs/dialog_print_using_printer.cpp new file mode 100644 index 00000000..09257bda --- /dev/null +++ b/eeschema/dialogs/dialog_print_using_printer.cpp @@ -0,0 +1,487 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + + +/** + * Class DIALOG_PRINT_USING_PRINTER + * offers to print a schematic dialog. + * + * Derived from DIALOG_PRINT_USING_PRINTER_base created by wxFormBuilder + */ +class DIALOG_PRINT_USING_PRINTER : public DIALOG_PRINT_USING_PRINTER_BASE +{ +public: + DIALOG_PRINT_USING_PRINTER( SCH_EDIT_FRAME* aParent ); + + SCH_EDIT_FRAME* GetParent() const + { + return ( SCH_EDIT_FRAME* ) wxWindow::GetParent(); + } + +private: + void OnCloseWindow( wxCloseEvent& event ); + void OnPageSetup( wxCommandEvent& event ); + void OnPrintPreview( wxCommandEvent& event ); + void OnPrintButtonClick( wxCommandEvent& event ); + void OnButtonCancelClick( wxCommandEvent& event ) { Close(); } + + void initDialog(); + void GetPrintOptions(); +}; + + + +/** + * Custom print out for printing schematics. + */ +class SCH_PRINTOUT : public wxPrintout +{ +private: + SCH_EDIT_FRAME* m_parent; + +public: + SCH_PRINTOUT( SCH_EDIT_FRAME* aParent, const wxString& aTitle ) : + wxPrintout( aTitle ) + { + wxASSERT( aParent != NULL ); + m_parent = aParent; + } + bool OnPrintPage( int page ); + bool HasPage( int page ); + bool OnBeginDocument( int startPage, int endPage ); + void GetPageInfo( int* minPage, int* maxPage, int* selPageFrom, int* selPageTo ); + void DrawPage( SCH_SCREEN* aScreen ); +}; + +/** + * Custom schematic print preview frame. + * This derived preview frame remembers its size and position during a session + */ +class SCH_PREVIEW_FRAME : public wxPreviewFrame +{ +public: + SCH_PREVIEW_FRAME( wxPrintPreview* aPreview, wxWindow* aParent, + const wxString& aTitle, const wxPoint& aPos = wxDefaultPosition, + const wxSize& aSize = wxDefaultSize ) : + wxPreviewFrame( aPreview, aParent, aTitle, aPos, aSize ) + { + } + + bool Show( bool show ) // overload + { + bool ret; + + // Show or hide the window. If hiding, save current position and size. + // If showing, use previous position and size. + if( show ) + { + ret = wxPreviewFrame::Show( show ); + + if( s_size.x != 0 && s_size.y != 0 ) + SetSize( s_pos.x, s_pos.y, s_size.x, s_size.y, 0 ); + } + else + { + // Save the dialog's position & size before hiding + s_size = GetSize(); + s_pos = GetPosition(); + + ret = wxPreviewFrame::Show( show ); + } + + return ret; + } + +private: + static wxPoint s_pos; + static wxSize s_size; +}; + +wxPoint SCH_PREVIEW_FRAME::s_pos; +wxSize SCH_PREVIEW_FRAME::s_size; + + +DIALOG_PRINT_USING_PRINTER::DIALOG_PRINT_USING_PRINTER( SCH_EDIT_FRAME* aParent ) : + DIALOG_PRINT_USING_PRINTER_BASE( aParent ) +{ + wxASSERT( aParent != NULL ); + + m_checkReference->SetValue( aParent->GetPrintSheetReference() ); + m_checkMonochrome->SetValue( aParent->GetPrintMonochrome() ); + initDialog(); + +#ifdef __WXMAC__ + // Problems with modal on wx-2.9 - Anyway preview is standard for OSX + m_buttonPreview->Hide(); +#endif + + GetSizer()->Fit( this ); +} + + +void DIALOG_PRINT_USING_PRINTER::initDialog() +{ + SCH_EDIT_FRAME* parent = GetParent(); + + // Initialize page specific print setup dialog settings. + const PAGE_INFO& pageInfo = parent->GetScreen()->GetPageSettings(); + wxPageSetupDialogData& pageSetupDialogData = parent->GetPageSetupData(); + + pageSetupDialogData.SetPaperId( pageInfo.GetPaperId() ); + + if( pageInfo.IsCustom() ) + { + if( pageInfo.IsPortrait() ) + pageSetupDialogData.SetPaperSize( wxSize( Mils2mm( pageInfo.GetWidthMils() ), + Mils2mm( pageInfo.GetHeightMils() ) ) ); + else + pageSetupDialogData.SetPaperSize( wxSize( Mils2mm( pageInfo.GetHeightMils() ), + Mils2mm( pageInfo.GetWidthMils() ) ) ); + } + + pageSetupDialogData.GetPrintData().SetOrientation( pageInfo.GetWxOrientation() ); + + if ( GetSizer() ) + GetSizer()->SetSizeHints( this ); + + // Rely on the policy in class DIALOG_SHIM, which centers the dialog + // initially during a runtime session but gives user the ability to move it in + // that session. + // This dialog may get moved and resized in Show(), but in case this is + // the first time, center it for starters. + Center(); + + m_buttonPrint->SetDefault(); // on linux, this is inadequate to determine + // what ENTER does. Must also SetFocus(). + m_buttonPrint->SetFocus(); +} + + +void DIALOG_PRINT_USING_PRINTER::GetPrintOptions() +{ + SCH_EDIT_FRAME* parent = GetParent(); + + parent->SetPrintMonochrome( m_checkMonochrome->IsChecked() ); + parent->SetPrintSheetReference( m_checkReference->IsChecked() ); +} + + +void DIALOG_PRINT_USING_PRINTER::OnCloseWindow( wxCloseEvent& event ) +{ + SCH_EDIT_FRAME* parent = GetParent(); + + if( !IsIconized() ) + { + parent->SetPrintDialogPosition( GetPosition() ); + parent->SetPrintDialogSize( GetSize() ); + } + + GetPrintOptions(); + + EndDialog( wxID_CANCEL ); +} + + +/* Open a dialog box for printer setup (printer options, page size ...) + */ +void DIALOG_PRINT_USING_PRINTER::OnPageSetup( wxCommandEvent& event ) +{ + SCH_EDIT_FRAME* parent = GetParent(); + + wxPageSetupDialog pageSetupDialog( this, &parent->GetPageSetupData() ); + + pageSetupDialog.ShowModal(); + + parent->GetPageSetupData() = pageSetupDialog.GetPageSetupDialogData(); +} + + +/* Open and display a previewer frame for printing + */ +void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event ) +{ + SCH_EDIT_FRAME* parent = GetParent(); + + GetPrintOptions(); + + // Pass two printout objects: for preview, and possible printing. + wxString title = _( "Preview" ); + wxPrintPreview* preview = new wxPrintPreview( new SCH_PRINTOUT( parent, title ), + new SCH_PRINTOUT( parent, title ), + &parent->GetPageSetupData().GetPrintData() ); + + if( preview == NULL ) + { + DisplayError( this, wxT( "Print preview error!" ) ); + return; + } + + preview->SetZoom( 100 ); + + SCH_PREVIEW_FRAME* frame = new SCH_PREVIEW_FRAME( preview, this, title ); + frame->SetMinSize( wxSize( 550, 350 ) ); + + // on first invocation in this runtime session, set to 2/3 size of my parent, + // but will be changed in Show() if not first time as will position. + frame->SetSize( (parent->GetSize() * 2) / 3 ); + frame->Center(); + + // On wxGTK, set the flag wxTOPLEVEL_EX_DIALOG is mandatory, if we want + // close the frame using the X box in caption, when the preview frame is run + // from a dialog + frame->SetExtraStyle( frame->GetExtraStyle() | wxTOPLEVEL_EX_DIALOG ); + + // We use here wxPreviewFrame_WindowModal option to make the wxPrintPreview frame + // modal for its caller only. + // An other reason is the fact when closing the frame without this option, + // all top level frames are reenabled. + // With this option, only the parent is reenabled. + // Reenabling all top level frames should be made by the parent dialog. + frame->InitializeWithModality( wxPreviewFrame_WindowModal ); + + frame->Raise(); // Needed on Ubuntu/Unity to display the frame + frame->Show( true ); +} + + +void DIALOG_PRINT_USING_PRINTER::OnPrintButtonClick( wxCommandEvent& event ) +{ + SCH_EDIT_FRAME* parent = GetParent(); + + GetPrintOptions(); + + wxPrintDialogData printDialogData( parent->GetPageSetupData().GetPrintData() ); + printDialogData.SetMaxPage( g_RootSheet->CountSheets() ); + + if( g_RootSheet->CountSheets() > 1 ) + printDialogData.EnablePageNumbers( true ); + + wxPrinter printer( &printDialogData ); + SCH_PRINTOUT printout( parent, _( "Print Schematic" ) ); + + if( !printer.Print( this, &printout, true ) ) + { + if( wxPrinter::GetLastError() == wxPRINTER_ERROR ) + wxMessageBox( _( "An error occurred attempting to print the schematic." ), + _( "Printing" ), wxOK ); + } + else + { + parent->GetPageSetupData() = printer.GetPrintDialogData().GetPrintData(); + } +} + + +bool SCH_PRINTOUT::OnPrintPage( int page ) +{ + wxString msg; + msg.Printf( _( "Print page %d" ), page ); + m_parent->ClearMsgPanel(); + m_parent->AppendMsgPanel( msg, wxEmptyString, CYAN ); + + SCH_SCREEN* screen = m_parent->GetScreen(); + SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); + SCH_SHEET_PATH list; + SCH_SHEET_LIST SheetList( NULL ); + SCH_SHEET_PATH* sheetpath = SheetList.GetSheet( page - 1 ); + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + m_parent->SetCurrentSheet( list ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + screen = m_parent->GetCurrentSheet().LastScreen(); + } + else + { + screen = NULL; + } + + if( screen == NULL ) + return false; + + DrawPage( screen ); + m_parent->SetCurrentSheet( oldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + + return true; +} + + +void SCH_PRINTOUT::GetPageInfo( int* minPage, int* maxPage, int* selPageFrom, int* selPageTo ) +{ + *minPage = *selPageFrom = 1; + *maxPage = *selPageTo = g_RootSheet->CountSheets(); +} + + +bool SCH_PRINTOUT::HasPage( int pageNum ) +{ + int pageCount; + + pageCount = g_RootSheet->CountSheets(); + if( pageCount >= pageNum ) + return true; + + return false; +} + + +bool SCH_PRINTOUT::OnBeginDocument( int startPage, int endPage ) +{ + if( !wxPrintout::OnBeginDocument( startPage, endPage ) ) + return false; + +#ifdef __WXDEBUG__ + wxLogDebug( wxT( "Printer name: " ) + + m_parent->GetPageSetupData().GetPrintData().GetPrinterName() ); + wxLogDebug( wxT( "Paper ID: %d" ), + m_parent->GetPageSetupData().GetPrintData().GetPaperId() ); + wxLogDebug( wxT( "Color: %d" ), + (int)m_parent->GetPageSetupData().GetPrintData().GetColour() ); + wxLogDebug( wxT( "Monochrome: %d" ), m_parent->GetPrintMonochrome() ); + wxLogDebug( wxT( "Orientation: %d:" ), + m_parent->GetPageSetupData().GetPrintData().GetOrientation() ); + wxLogDebug( wxT( "Quality: %d"), + m_parent->GetPageSetupData().GetPrintData().GetQuality() ); +#endif + + return true; +} + + +/* + * This is the real print function: print the active screen + */ +void SCH_PRINTOUT::DrawPage( SCH_SCREEN* aScreen ) +{ + int oldZoom; + wxPoint tmp_startvisu; + wxSize pageSizeIU; // Page size in internal units + wxPoint old_org; + EDA_RECT oldClipBox; + wxRect fitRect; + wxDC* dc = GetDC(); + EDA_DRAW_PANEL* panel = m_parent->GetCanvas(); + + wxBusyCursor dummy; + + // Save current scale factor, offsets, and clip box. + tmp_startvisu = aScreen->m_StartVisu; + oldZoom = aScreen->GetZoom(); + old_org = aScreen->m_DrawOrg; + + oldClipBox = *panel->GetClipBox(); + + // Change clip box to print the whole page. + #define MAX_VALUE (INT_MAX/2) // MAX_VALUE is the max we can use in an integer + // and that allows calculations without overflow + panel->SetClipBox( EDA_RECT( wxPoint( 0, 0 ), wxSize( MAX_VALUE, MAX_VALUE ) ) ); + + // Change scale factor and offset to print the whole page. + bool printReference = m_parent->GetPrintSheetReference(); + + pageSizeIU = aScreen->GetPageSettings().GetSizeIU(); + FitThisSizeToPaper( pageSizeIU ); + fitRect = GetLogicalPaperRect(); + + wxLogDebug( wxT( "Fit rectangle: x = %d, y = %d, w = %d, h = %d" ), + fitRect.x, fitRect.y, fitRect.width, fitRect.height ); + + // When is the actual paper size does not match the schematic page + // size, the drawing is not perfectly centered on X or Y axis. + // Give a draw offset centers the schematic page on the paper draw area + // Because the sizes are fitted, only an Y or X offset is needed + // and both are 0 when sizes are identical. + // Y or Y offset is not null when the X/Y size ratio differs between + // the actual paper size and the schematic page + int xoffset = ( fitRect.width - pageSizeIU.x ) / 2; + + // For an obscure reason, OffsetLogicalOrigin creates issues, + // under some circumstances, when yoffset is not always null + // and changes from a page to an other page + // This is only a workaround, not a fix + // see https://bugs.launchpad.net/kicad/+bug/1464773 + // xoffset does not create issues. +#if 0 // FIX ME + int yoffset = ( fitRect.height - pageSizeIU.y ) / 2; +#else + // the Y centering will be not perfect, but this is less annoying + // than a blank page or a buggy centering + int yoffset = 0; +#endif + OffsetLogicalOrigin( xoffset, yoffset ); + + GRResetPenAndBrush( dc ); + + if( m_parent->GetPrintMonochrome() ) + GRForceBlackPen( true ); + + aScreen->m_IsPrinting = true; + + EDA_COLOR_T bg_color = m_parent->GetDrawBgColor(); + + aScreen->Draw( panel, dc, (GR_DRAWMODE) 0 ); + + if( printReference ) + m_parent->DrawWorkSheet( dc, aScreen, GetDefaultLineThickness(), + IU_PER_MILS, aScreen->GetFileName() ); + + m_parent->SetDrawBgColor( bg_color ); + aScreen->m_IsPrinting = false; + panel->SetClipBox( oldClipBox ); + + GRForceBlackPen( false ); + + aScreen->m_StartVisu = tmp_startvisu; + aScreen->m_DrawOrg = old_org; + aScreen->SetZoom( oldZoom ); +} + + +int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller ) +{ + DIALOG_PRINT_USING_PRINTER dlg( aCaller ); + + return dlg.ShowModal(); +} diff --git a/eeschema/dialogs/dialog_print_using_printer_base.cpp b/eeschema/dialogs/dialog_print_using_printer_base.cpp new file mode 100644 index 00000000..6a163b1e --- /dev/null +++ b/eeschema/dialogs/dialog_print_using_printer_base.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_print_using_printer_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_PRINT_USING_PRINTER_BASE::DIALOG_PRINT_USING_PRINTER_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( wxHORIZONTAL ); + + wxBoxSizer* bleftSizer; + bleftSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("Print options:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + m_staticText1->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bleftSizer->Add( m_staticText1, 0, wxTOP|wxRIGHT, 5 ); + + m_checkReference = new wxCheckBox( this, wxID_ANY, _("Print sheet &reference and title block"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkReference->SetValue(true); + m_checkReference->SetToolTip( _("Print (or not) the Frame references.") ); + + bleftSizer->Add( m_checkReference, 0, wxALL, 10 ); + + m_checkMonochrome = new wxCheckBox( this, wxID_ANY, _("Print in &black and white only"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkMonochrome->SetValue(true); + bleftSizer->Add( m_checkMonochrome, 0, wxBOTTOM|wxRIGHT|wxLEFT, 10 ); + + + bMainSizer->Add( bleftSizer, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 12 ); + + wxBoxSizer* bbuttonsSizer; + bbuttonsSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonPageSetup = new wxButton( this, wxID_ANY, _("Page Setup"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttonPageSetup, 0, wxALL|wxEXPAND, 5 ); + + m_buttonPreview = new wxButton( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttonPreview, 0, wxALL|wxEXPAND, 5 ); + + m_buttonPrint = new wxButton( this, wxID_ANY, _("Print"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttonPrint, 0, wxALL|wxEXPAND, 5 ); + + m_buttonQuit = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); + bbuttonsSizer->Add( m_buttonQuit, 0, wxALL|wxEXPAND, 5 ); + + + bMainSizer->Add( bbuttonsSizer, 0, wxALL, 12 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnCloseWindow ) ); + m_buttonPageSetup->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPageSetup ), NULL, this ); + m_buttonPreview->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPrintPreview ), NULL, this ); + m_buttonPrint->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPrintButtonClick ), NULL, this ); + m_buttonQuit->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnButtonCancelClick ), NULL, this ); +} + +DIALOG_PRINT_USING_PRINTER_BASE::~DIALOG_PRINT_USING_PRINTER_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnCloseWindow ) ); + m_buttonPageSetup->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPageSetup ), NULL, this ); + m_buttonPreview->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPrintPreview ), NULL, this ); + m_buttonPrint->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnPrintButtonClick ), NULL, this ); + m_buttonQuit->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PRINT_USING_PRINTER_BASE::OnButtonCancelClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_print_using_printer_base.fbp b/eeschema/dialogs/dialog_print_using_printer_base.fbp new file mode 100644 index 00000000..cf785e1e --- /dev/null +++ b/eeschema/dialogs/dialog_print_using_printer_base.fbp @@ -0,0 +1,732 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_print_using_printer_base + 1000 + none + 1 + dialog_print_schematic + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + -1,-1 + DIALOG_PRINT_USING_PRINTER_BASE + + 388,185 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Print + + + + + + + + + + + + + + OnCloseWindow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxHORIZONTAL + none + + 12 + wxBOTTOM|wxEXPAND|wxLEFT|wxTOP + 1 + + + bleftSizer + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Print options: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Print sheet &reference and title block + + 0 + + + 0 + + 1 + m_checkReference + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Print (or not) the Frame references. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Print in &black and white only + + 0 + + + 0 + + 1 + m_checkMonochrome + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + wxALL + 0 + + + bbuttonsSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Page Setup + + 0 + + + 0 + + 1 + m_buttonPageSetup + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnPageSetup + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Preview + + 0 + + + 0 + + 1 + m_buttonPreview + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnPrintPreview + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Print + + 0 + + + 0 + + 1 + m_buttonPrint + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnPrintButtonClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Close + + 0 + + + 0 + + 1 + m_buttonQuit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnButtonCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_print_using_printer_base.h b/eeschema/dialogs/dialog_print_using_printer_base.h new file mode 100644 index 00000000..49994cf1 --- /dev/null +++ b/eeschema/dialogs/dialog_print_using_printer_base.h @@ -0,0 +1,61 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_PRINT_USING_PRINTER_BASE_H__ +#define __DIALOG_PRINT_USING_PRINTER_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_PRINT_USING_PRINTER_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_PRINT_USING_PRINTER_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText1; + wxCheckBox* m_checkReference; + wxCheckBox* m_checkMonochrome; + wxButton* m_buttonPageSetup; + wxButton* m_buttonPreview; + wxButton* m_buttonPrint; + wxButton* m_buttonQuit; + + // Virtual event handlers, overide them in your derived class + virtual void OnCloseWindow( wxCloseEvent& event ) { event.Skip(); } + virtual void OnPageSetup( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPrintPreview( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPrintButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnButtonCancelClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_PRINT_USING_PRINTER_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Print"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 388,185 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_PRINT_USING_PRINTER_BASE(); + +}; + +#endif //__DIALOG_PRINT_USING_PRINTER_BASE_H__ diff --git a/eeschema/dialogs/dialog_rescue_each.cpp b/eeschema/dialogs/dialog_rescue_each.cpp new file mode 100644 index 00000000..73238e74 --- /dev/null +++ b/eeschema/dialogs/dialog_rescue_each.cpp @@ -0,0 +1,316 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Chris Pavlina + * Copyright (C) 2015 Kicad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class DIALOG_RESCUE_EACH: public DIALOG_RESCUE_EACH_BASE +{ +public: + /** + * Constructor + * This dialog asks the user which rescuable, cached parts he wants to rescue. + * Any rejects will be pruned from aCandidates. + * @param aCaller - the SCH_EDIT_FRAME calling this + * @param aRescuer - the active RESCUER instance + * @param aAskShowAgain - if true, a "Never Show Again" button will be included + */ + DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescuer, bool aAskShowAgain ); + + ~DIALOG_RESCUE_EACH(); + +private: + SCH_EDIT_FRAME* m_Parent; + wxConfigBase* m_Config; + RESCUER* m_Rescuer; + bool m_AskShowAgain; + + bool TransferDataToWindow(); + bool TransferDataFromWindow(); + void PopulateConflictList(); + void PopulateInstanceList(); + void OnConflictSelect( wxDataViewEvent& event ); + void OnNeverShowClick( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); + void OnHandleCachePreviewRepaint( wxPaintEvent& aRepaintEvent ); + void OnHandleLibraryPreviewRepaint( wxPaintEvent& aRepaintEvent ); + void OnDialogResize( wxSizeEvent& aSizeEvent ); + void renderPreview( LIB_PART* aComponent, int aUnit, wxPanel* panel ); +}; + + +DIALOG_RESCUE_EACH::DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescuer, + bool aAskShowAgain ) + : DIALOG_RESCUE_EACH_BASE( aParent ), + m_Parent( aParent ), + m_Rescuer( &aRescuer ), + m_AskShowAgain( aAskShowAgain ) +{ + m_Config = Kiface().KifaceSettings(); + m_stdButtonsOK->SetDefault(); + + // Set the info message, customized to include the proper suffix. + wxString info_message = + _( "It looks like this project was made using older schematic component libraries.\n" + "Some parts may need to be relinked to a different symbol name, and some symbols\n" + "may need to be \"rescued\" (cloned and renamed) into a new library.\n" + "\n" + "The following changes are recommended to update the project." ); + m_lblInfo->SetLabel( info_message ); + + m_componentViewOld->SetLayoutDirection( wxLayout_LeftToRight ); + m_componentViewNew->SetLayoutDirection( wxLayout_LeftToRight ); +} + + +DIALOG_RESCUE_EACH::~DIALOG_RESCUE_EACH() +{ +} + + +bool DIALOG_RESCUE_EACH::TransferDataToWindow() +{ + if( !wxDialog::TransferDataToWindow() ) + return false; + + m_ListOfConflicts->AppendToggleColumn( _( "Accept" ) ); + m_ListOfConflicts->AppendTextColumn( _( "Symbol" ) ); + m_ListOfConflicts->AppendTextColumn( _( "Action" ) ); + m_ListOfInstances->AppendTextColumn( _( "Reference" ) ); + m_ListOfInstances->AppendTextColumn( _( "Value" ) ); + PopulateConflictList(); + PopulateInstanceList(); + + if( !m_AskShowAgain ) + m_btnNeverShowAgain->Hide(); + + GetSizer()->Layout(); + GetSizer()->Fit( this ); + GetSizer()->SetSizeHints( this ); + Centre(); + + return true; +} + + +void DIALOG_RESCUE_EACH::PopulateConflictList() +{ + wxVector data; + BOOST_FOREACH( RESCUE_CANDIDATE& each_candidate, m_Rescuer->m_all_candidates ) + { + data.clear(); + data.push_back( wxVariant( true ) ); + data.push_back( each_candidate.GetRequestedName() ); + data.push_back( each_candidate.GetActionDescription() ); + + m_ListOfConflicts->AppendItem( data ); + } + + if( !m_Rescuer->m_all_candidates.empty() ) + { + // Select the first choice + m_ListOfConflicts->SelectRow( 0 ); + } +} + + +void DIALOG_RESCUE_EACH::PopulateInstanceList() +{ + m_ListOfInstances->DeleteAllItems(); + + int row = m_ListOfConflicts->GetSelectedRow(); + + if( row == wxNOT_FOUND ) + row = 0; + + RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row]; + + wxVector data; + BOOST_FOREACH( SCH_COMPONENT* each_component, *m_Rescuer->GetComponents() ) + { + if( each_component->GetPartName() != selected_part.GetRequestedName() ) + continue; + + SCH_FIELD* valueField = each_component->GetField( 1 ); + + data.clear(); + data.push_back( each_component->GetRef( & m_Parent->GetCurrentSheet() ) ); + data.push_back( valueField ? valueField->GetText() : wxT( "" ) ); + m_ListOfInstances->AppendItem( data ); + + } +} + + +void DIALOG_RESCUE_EACH::OnHandleCachePreviewRepaint( wxPaintEvent& aRepaintEvent ) +{ + int row = m_ListOfConflicts->GetSelectedRow(); + + if( row == wxNOT_FOUND ) + row = 0; + + RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row]; + + if( selected_part.GetCacheCandidate() ) + renderPreview( selected_part.GetCacheCandidate(), 0, m_componentViewOld ); +} + + +void DIALOG_RESCUE_EACH::OnHandleLibraryPreviewRepaint( wxPaintEvent& aRepaintEvent ) +{ + int row = m_ListOfConflicts->GetSelectedRow(); + + if( row == wxNOT_FOUND ) + row = 0; + + RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row]; + + if( selected_part.GetLibCandidate() ) + renderPreview( selected_part.GetLibCandidate(), 0, m_componentViewNew ); +} + + +void DIALOG_RESCUE_EACH::OnDialogResize( wxSizeEvent& aSizeEvent ) +{ + // Placeholer - I was previously doing some extra reflow here. + DIALOG_RESCUE_EACH_BASE::OnDialogResize( aSizeEvent ); +} + + +// Render the preview in our m_componentView. If this gets more complicated, we should +// probably have a derived class from wxPanel; but this keeps things local. +// Call it only from a Paint Event, because we are using a wxPaintDC to draw the component +void DIALOG_RESCUE_EACH::renderPreview( LIB_PART* aComponent, int aUnit, wxPanel* aPanel ) +{ + wxPaintDC dc( aPanel ); + EDA_COLOR_T bgcolor = m_Parent->GetDrawBgColor(); + + dc.SetBackground( bgcolor == BLACK ? *wxBLACK_BRUSH : *wxWHITE_BRUSH ); + dc.Clear(); + + if( aComponent == NULL ) + return; + + if( aUnit <= 0 ) + aUnit = 1; + + const wxSize dc_size = dc.GetSize(); + dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 ); + + // Find joint bounding box for everything we are about to draw. + EDA_RECT bBox = aComponent->GetBoundingBox( aUnit, /* deMorganConvert */ 1 ); + const double xscale = (double) dc_size.x / bBox.GetWidth(); + const double yscale = (double) dc_size.y / bBox.GetHeight(); + const double scale = std::min( xscale, yscale ) * 0.85; + + dc.SetUserScale( scale, scale ); + + wxPoint offset = - bBox.Centre(); + + // Avoid rendering when either dimension is zero + int width, height; + + dc.GetSize( &width, &height ); + if( !width || !height ) + return; + + aComponent->Draw( NULL, &dc, offset, aUnit, /* deMorganConvert */ 1, GR_COPY, + UNSPECIFIED_COLOR, DefaultTransform, true, true, false ); +} + + +void DIALOG_RESCUE_EACH::OnConflictSelect( wxDataViewEvent& aEvent ) +{ + // wxformbuilder connects this event to the _dialog_, not the data view. + // Make sure the correct item triggered it, otherwise we trigger recursively + // and get a stack overflow. + if( aEvent.GetEventObject() != m_ListOfConflicts ) + return; + + PopulateInstanceList(); + + m_componentViewOld->Refresh(); + m_componentViewNew->Refresh(); +} + + +bool DIALOG_RESCUE_EACH::TransferDataFromWindow() +{ + if( !wxDialog::TransferDataFromWindow() ) + return false; + + for( size_t index = 0; index < m_Rescuer->GetCandidateCount(); ++index ) + { + wxVariant val; + m_ListOfConflicts->GetValue( val, index, 0 ); + bool rescue_part = val.GetBool(); + + if( rescue_part ) + m_Rescuer->m_chosen_candidates.push_back( &m_Rescuer->m_all_candidates[index] ); + } + return true; +} + + +void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent ) +{ + wxMessageDialog dlg( m_Parent, + _( "Stop showing this tool?\n" + "No changes will be made.\n\n" + "This setting can be changed from the \"Component Libraries\" dialog,\n" + "and the tool can be activated manually from the \"Tools\" menu." ), + _( "Rescue Components" ), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ); + int resp = dlg.ShowModal (); + + if( resp == wxID_YES ) + { + m_Config->Write( RESCUE_NEVER_SHOW_KEY, true ); + m_Rescuer->m_chosen_candidates.clear(); + Close(); + } +} + + +void DIALOG_RESCUE_EACH::OnCancelClick( wxCommandEvent& aEvent ) +{ + m_Rescuer->m_chosen_candidates.clear(); + DIALOG_RESCUE_EACH_BASE::OnCancelClick( aEvent ); +} + + +int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, RESCUER& aRescuer, bool aAskShowAgain ) +{ + DIALOG_RESCUE_EACH dlg( aCaller, aRescuer, aAskShowAgain ); + return dlg.ShowModal(); +} diff --git a/eeschema/dialogs/dialog_rescue_each_base.cpp b/eeschema/dialogs/dialog_rescue_each_base.cpp new file mode 100644 index 00000000..99cdbcc0 --- /dev/null +++ b/eeschema/dialogs/dialog_rescue_each_base.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 13 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_rescue_each_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_RESCUE_EACH_BASE::DIALOG_RESCUE_EACH_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( 450,100 ), wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + m_lblInfo = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_lblInfo->Wrap( 500 ); + bSizerMain->Add( m_lblInfo, 0, wxALL|wxEXPAND, 5 ); + + m_staticText5 = new wxStaticText( this, wxID_ANY, _("Symbols to update:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + m_staticText5->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizerMain->Add( m_staticText5, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_ListOfConflicts = new wxDataViewListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + bSizerMain->Add( m_ListOfConflicts, 2, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticText4 = new wxStaticText( this, wxID_ANY, _("Instances of this symbol:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + m_staticText4->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizerMain->Add( m_staticText4, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_ListOfInstances = new wxDataViewListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + bSizerMain->Add( m_ListOfInstances, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerView; + bSizerView = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizer6; + bSizer6 = new wxBoxSizer( wxVERTICAL ); + + m_staticText2 = new wxStaticText( this, wxID_ANY, _("Cached Part:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + m_staticText2->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizer6->Add( m_staticText2, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_componentViewOld = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER ); + m_componentViewOld->SetMinSize( wxSize( 150,150 ) ); + + bSizer6->Add( m_componentViewOld, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizerView->Add( bSizer6, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizer7; + bSizer7 = new wxBoxSizer( wxVERTICAL ); + + m_staticText3 = new wxStaticText( this, wxID_ANY, _("Library Part:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + m_staticText3->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizer7->Add( m_staticText3, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_componentViewNew = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER ); + m_componentViewNew->SetMinSize( wxSize( 150,150 ) ); + + bSizer7->Add( m_componentViewNew, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizerView->Add( bSizer7, 1, wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerView, 2, wxEXPAND, 5 ); + + wxBoxSizer* bSizer5; + bSizer5 = new wxBoxSizer( wxHORIZONTAL ); + + m_btnNeverShowAgain = new wxButton( this, wxID_ANY, _("Never Show Again"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer5->Add( m_btnNeverShowAgain, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bSizer5->Add( 0, 0, 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(); + + bSizer5->Add( m_stdButtons, 0, wxALL|wxEXPAND, 5 ); + + + bSizerMain->Add( bSizer5, 0, wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_RESCUE_EACH_BASE::OnDialogResize ) ); + this->Connect( wxID_ANY, wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_RESCUE_EACH_BASE::OnConflictSelect ) ); + m_componentViewOld->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_RESCUE_EACH_BASE::OnHandleCachePreviewRepaint ), NULL, this ); + m_componentViewNew->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_RESCUE_EACH_BASE::OnHandleLibraryPreviewRepaint ), NULL, this ); + m_btnNeverShowAgain->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_RESCUE_EACH_BASE::OnNeverShowClick ), NULL, this ); + m_stdButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_RESCUE_EACH_BASE::OnCancelClick ), NULL, this ); +} + +DIALOG_RESCUE_EACH_BASE::~DIALOG_RESCUE_EACH_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_RESCUE_EACH_BASE::OnDialogResize ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_RESCUE_EACH_BASE::OnConflictSelect ) ); + m_componentViewOld->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_RESCUE_EACH_BASE::OnHandleCachePreviewRepaint ), NULL, this ); + m_componentViewNew->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_RESCUE_EACH_BASE::OnHandleLibraryPreviewRepaint ), NULL, this ); + m_btnNeverShowAgain->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_RESCUE_EACH_BASE::OnNeverShowClick ), NULL, this ); + m_stdButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_RESCUE_EACH_BASE::OnCancelClick ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_rescue_each_base.fbp b/eeschema/dialogs/dialog_rescue_each_base.fbp new file mode 100644 index 00000000..5199216f --- /dev/null +++ b/eeschema/dialogs/dialog_rescue_each_base.fbp @@ -0,0 +1,978 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_rescue_each_base + 1000 + none + 1 + dialog_rescue_each_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 450,100 + DIALOG_RESCUE_EACH_BASE + + 529,593 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Project Rescue Helper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnDialogResize + + + + bSizerMain + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_lblInfo + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + 500 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Symbols to update: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 2 + + + + 1 + 1 + + + 0 + wxID_ANY + + + m_ListOfConflicts + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + OnConflictSelect + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Instances of this symbol: + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + + + 1 + 1 + + + 0 + wxID_ANY + + + m_ListOfInstances + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 2 + + + bSizerView + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizer6 + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Cached Part: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 150,150 + 1 + m_componentViewOld + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER + + + + + + + + + + + + + + + + + OnHandleCachePreviewRepaint + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer7 + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + Library Part: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 150,150 + 1 + m_componentViewNew + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER + + + + + + + + + + + + + + + + + OnHandleLibraryPreviewRepaint + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer5 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Never Show Again + + 0 + + + 0 + + 1 + m_btnNeverShowAgain + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnNeverShowClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdButtons + protected + + OnCancelClick + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_rescue_each_base.h b/eeschema/dialogs/dialog_rescue_each_base.h new file mode 100644 index 00000000..40d1b112 --- /dev/null +++ b/eeschema/dialogs/dialog_rescue_each_base.h @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 13 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_RESCUE_EACH_BASE_H__ +#define __DIALOG_RESCUE_EACH_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_RESCUE_EACH_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_RESCUE_EACH_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_lblInfo; + wxStaticText* m_staticText5; + wxDataViewListCtrl* m_ListOfConflicts; + wxStaticText* m_staticText4; + wxDataViewListCtrl* m_ListOfInstances; + wxStaticText* m_staticText2; + wxPanel* m_componentViewOld; + wxStaticText* m_staticText3; + wxPanel* m_componentViewNew; + wxButton* m_btnNeverShowAgain; + wxStdDialogButtonSizer* m_stdButtons; + wxButton* m_stdButtonsOK; + wxButton* m_stdButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnDialogResize( wxSizeEvent& event ) { event.Skip(); } + virtual void OnConflictSelect( wxDataViewEvent& event ) { event.Skip(); } + virtual void OnHandleCachePreviewRepaint( wxPaintEvent& event ) { event.Skip(); } + virtual void OnHandleLibraryPreviewRepaint( wxPaintEvent& event ) { event.Skip(); } + virtual void OnNeverShowClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_RESCUE_EACH_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Project Rescue Helper"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 529,593 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_RESCUE_EACH_BASE(); + +}; + +#endif //__DIALOG_RESCUE_EACH_BASE_H__ diff --git a/eeschema/dialogs/dialog_sch_edit_sheet_pin.cpp b/eeschema/dialogs/dialog_sch_edit_sheet_pin.cpp new file mode 100644 index 00000000..9b44c994 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_edit_sheet_pin.cpp @@ -0,0 +1,60 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Wayne Stambaugh + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 + + +static wxString sheetPinTypes[] = +{ + _( "Input" ), + _( "Output" ), + _( "Bidirectional" ), + _( "Tri-state" ), + _( "Passive" ) +}; + + +#define SHEET_PIN_TYPE_CNT ( sizeof( sheetPinTypes ) / sizeof( wxString ) ) + + +DIALOG_SCH_EDIT_SHEET_PIN::DIALOG_SCH_EDIT_SHEET_PIN( wxWindow* parent ) : + DIALOG_SCH_EDIT_SHEET_PIN_BASE( parent ) +{ + for( size_t i = 0; i < SHEET_PIN_TYPE_CNT; i++ ) + m_choiceConnectionType->Append( sheetPinTypes[ i ] ); + + m_choiceConnectionType->SetSelection( 0 ); + m_textName->SetFocus(); + m_sdbSizerOK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); + + // On some windows manager (Unity, XFCE), this dialog is + // not always raised, depending on this dialog is run. + // Force it to be raised + Raise(); +} diff --git a/eeschema/dialogs/dialog_sch_edit_sheet_pin.h b/eeschema/dialogs/dialog_sch_edit_sheet_pin.h new file mode 100644 index 00000000..fc35864d --- /dev/null +++ b/eeschema/dialogs/dialog_sch_edit_sheet_pin.h @@ -0,0 +1,59 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Wayne Stambaugh + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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_sch_edit_sheet_pin__ +#define __dialog_sch_edit_sheet_pin__ + + +/** + * @file + * Subclass of DIALOG_SCH_EDIT_SHEET_PIN_BASE, which is generated by wxFormBuilder. + */ + + +#include + + +class DIALOG_SCH_EDIT_SHEET_PIN : public DIALOG_SCH_EDIT_SHEET_PIN_BASE +{ +public: + DIALOG_SCH_EDIT_SHEET_PIN( wxWindow* parent ); + + void SetLabelName( const wxString& aName ) { m_textName->SetValue( aName ); } + wxString GetLabelName() const { return m_textName->GetValue(); } + + void SetTextHeight( const wxString& aHeight ) { m_textHeight->SetValue( aHeight ); } + wxString GetTextHeight() const { return m_textHeight->GetValue(); } + + void SetTextWidth( const wxString& aWidth ) { m_textWidth->SetValue( aWidth ); } + wxString GetTextWidth() const { return m_textWidth->GetValue(); } + + void SetConnectionType( int aType ) { m_choiceConnectionType->SetSelection( aType ); } + int GetConnectionType() const { return m_choiceConnectionType->GetCurrentSelection(); } + + void SetTextHeightUnits( const wxString& aUnit ) { m_staticHeightUnits->SetLabel( aUnit ); } + void SetTextWidthUnits( const wxString& aUnit ) { m_staticWidthUnits->SetLabel( aUnit ); } +}; + +#endif // __dialog_sch_edit_sheet_pin__ diff --git a/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.cpp b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.cpp new file mode 100644 index 00000000..8fe85fd4 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.cpp @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_sch_edit_sheet_pin_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_SCH_EDIT_SHEET_PIN_BASE::DIALOG_SCH_EDIT_SHEET_PIN_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( 350,-1 ), wxDefaultSize ); + + wxBoxSizer* m_mainSizer; + m_mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* m_nameSizer; + m_nameSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer( 4, 3, 0, 0 ); + fgSizer1->AddGrowableCol( 1 ); + fgSizer1->SetFlexibleDirection( wxBOTH ); + fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("Name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + fgSizer1->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 6 ); + + m_textName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textName->SetMaxLength( 0 ); + fgSizer1->Add( m_textName, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 6 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 6 ); + + m_staticText2 = new wxStaticText( this, wxID_ANY, _("Text height:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + fgSizer1->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_textHeight = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textHeight->SetMaxLength( 0 ); + fgSizer1->Add( m_textHeight, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_staticHeightUnits = new wxStaticText( this, wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticHeightUnits->Wrap( -1 ); + fgSizer1->Add( m_staticHeightUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_staticText5 = new wxStaticText( this, wxID_ANY, _("Text width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + fgSizer1->Add( m_staticText5, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_textWidth = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textWidth->SetMaxLength( 0 ); + fgSizer1->Add( m_textWidth, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_staticWidthUnits = new wxStaticText( this, wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticWidthUnits->Wrap( -1 ); + fgSizer1->Add( m_staticWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_staticText3 = new wxStaticText( this, wxID_ANY, _("Connection type:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + fgSizer1->Add( m_staticText3, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + wxArrayString m_choiceConnectionTypeChoices; + m_choiceConnectionType = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceConnectionTypeChoices, 0 ); + m_choiceConnectionType->SetSelection( 0 ); + fgSizer1->Add( m_choiceConnectionType, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 6 ); + + + m_nameSizer->Add( fgSizer1, 1, wxEXPAND, 6 ); + + + m_mainSizer->Add( m_nameSizer, 1, wxALL|wxEXPAND, 6 ); + + + m_mainSizer->Add( 0, 0, 0, wxALL|wxEXPAND, 3 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + m_mainSizer->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 6 ); + + + this->SetSizer( m_mainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +DIALOG_SCH_EDIT_SHEET_PIN_BASE::~DIALOG_SCH_EDIT_SHEET_PIN_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.fbp b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.fbp new file mode 100644 index 00000000..f5c7863a --- /dev/null +++ b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.fbp @@ -0,0 +1,1043 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_sch_edit_sheet_pin_base + 1000 + none + 1 + dialog_sch_edit_sheet_pin + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 350,-1 + DIALOG_SCH_EDIT_SHEET_PIN_BASE + + 350,189 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Sheet Pin Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m_mainSizer + wxVERTICAL + none + + 6 + wxALL|wxEXPAND + 1 + + + m_nameSizer + wxHORIZONTAL + none + + 6 + wxEXPAND + 1 + + 3 + wxBOTH + 1 + + 0 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 4 + 0 + + 6 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Name: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text height: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textHeight + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NUMERIC + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + units + + 0 + + + 0 + + 1 + m_staticHeightUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text width: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textWidth + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + units + + 0 + + + 0 + + 1 + m_staticWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Connection type: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceConnectionType + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + + + 3 + wxALL|wxEXPAND + 0 + + 0 + protected + 0 + + + + 6 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.h b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.h new file mode 100644 index 00000000..fb19f936 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_edit_sheet_pin_base.h @@ -0,0 +1,61 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 5 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_SCH_EDIT_SHEET_PIN_BASE_H__ +#define __DIALOG_SCH_EDIT_SHEET_PIN_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_SCH_EDIT_SHEET_PIN_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_SCH_EDIT_SHEET_PIN_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText1; + wxTextCtrl* m_textName; + wxStaticText* m_staticText2; + wxTextCtrl* m_textHeight; + wxStaticText* m_staticHeightUnits; + wxStaticText* m_staticText5; + wxTextCtrl* m_textWidth; + wxStaticText* m_staticWidthUnits; + wxStaticText* m_staticText3; + wxChoice* m_choiceConnectionType; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + public: + + DIALOG_SCH_EDIT_SHEET_PIN_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Sheet Pin Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 350,189 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_SCH_EDIT_SHEET_PIN_BASE(); + +}; + +#endif //__DIALOG_SCH_EDIT_SHEET_PIN_BASE_H__ diff --git a/eeschema/dialogs/dialog_sch_sheet_props.cpp b/eeschema/dialogs/dialog_sch_sheet_props.cpp new file mode 100644 index 00000000..795a56af --- /dev/null +++ b/eeschema/dialogs/dialog_sch_sheet_props.cpp @@ -0,0 +1,61 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 +#include +#include + + +DIALOG_SCH_SHEET_PROPS::DIALOG_SCH_SHEET_PROPS( wxWindow* parent ) : + DIALOG_SCH_SHEET_PROPS_BASE( parent ) +{ + m_textFileName->SetValidator( FILE_NAME_WITH_PATH_CHAR_VALIDATOR() ); + m_textFileName->SetFocus(); + m_sdbSizer1OK->SetDefault(); + + FixOSXCancelButtonIssue(); + + // Now all widgets have the size fixed, call FinishDialogSettings + FinishDialogSettings(); +} + + +void DIALOG_SCH_SHEET_PROPS::SetFileName( const wxString& aFileName ) +{ + // Filenames are stored using unix notation + wxString fname = aFileName; +#ifdef __WINDOWS__ + fname.Replace( wxT("/"), wxT("\\") ); +#endif + m_textFileName->SetValue( fname ); +} + + +const wxString DIALOG_SCH_SHEET_PROPS::GetFileName() +{ + // Filenames are stored using unix notation + wxString fname = m_textFileName->GetValue(); + fname.Replace( wxT("\\"), wxT("/") ); + return fname; +} diff --git a/eeschema/dialogs/dialog_sch_sheet_props.fbp b/eeschema/dialogs/dialog_sch_sheet_props.fbp new file mode 100644 index 00000000..93347cc4 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_sheet_props.fbp @@ -0,0 +1,1503 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + table + dialog_sch_sheet_props_base + 1000 + none + 1 + dialog_sch_sheet_props + + . + + 1 + 1 + 1 + 1 + UI + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 500,150 + DIALOG_SCH_SHEET_PROPS_BASE + + 519,187 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Schematic Sheet Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bupperSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 6 + wxBOTH + 1 + + 0 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &File name: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxBOTTOM + 5 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + 200,-1 + 1 + m_textFileName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_HORIZONTAL|wxALL + 1 + + 0 + protected + 0 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Si&ze: + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textFileNameSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + units + + 0 + + + 0 + + 1 + m_staticFileNameSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Sheet name: + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxEXPAND|wxTOP|wxBOTTOM + 5 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textSheetName + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + + 0 + protected + 0 + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Size: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textSheetNameSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + units + + 0 + + + 0 + + 1 + m_staticSheetNameSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline3 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Unique timestamp: + + 0 + + + 0 + + 1 + m_staticTextTimeStamp + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrlTimeStamp + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 0 + protected + 0 + + + + 5 + wxEXPAND|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_sch_sheet_props.h b/eeschema/dialogs/dialog_sch_sheet_props.h new file mode 100644 index 00000000..e4aa3a6e --- /dev/null +++ b/eeschema/dialogs/dialog_sch_sheet_props.h @@ -0,0 +1,80 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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_sch_sheet_props__ +#define __dialog_sch_sheet_props__ + +/** + * @file + * Subclass of DIALOG_SCH_SHEET_PROPS_BASE, which is generated by wxFormBuilder. + */ + +#include + +/** Implementing DIALOG_SCH_SHEET_PROPS_BASE */ +class DIALOG_SCH_SHEET_PROPS : public DIALOG_SCH_SHEET_PROPS_BASE +{ +public: + /** Constructor */ + DIALOG_SCH_SHEET_PROPS( wxWindow* parent ); + + void SetFileName( const wxString& aFileName ); + const wxString GetFileName(); + + void SetSheetName( const wxString& aSheetName ) + { + m_textSheetName->SetValue( aSheetName ); + } + wxString GetSheetName() { return m_textSheetName->GetValue(); } + + void SetFileNameTextSize( const wxString& aTextSize ) + { + m_textFileNameSize->SetValue( aTextSize ); + } + wxString GetFileNameTextSize() { return m_textFileNameSize->GetValue(); } + + void SetSheetNameTextSize( const wxString& aTextSize ) + { + m_textSheetNameSize->SetValue( aTextSize ); + } + wxString GetSheetNameTextSize() { return m_textSheetNameSize->GetValue(); } + + void SetFileNameTextSizeUnits(const wxString& aUnits) + { + m_staticFileNameSizeUnits->SetLabel( aUnits ); + } + + void SetSheetNameTextSizeUnits(const wxString& aUnits) + { + m_staticSheetNameSizeUnits->SetLabel( aUnits ); + } + + void SetSheetTimeStamp(const wxString& aTimeStamp) + { + m_textCtrlTimeStamp->SetValue( aTimeStamp ); + } + +}; + +#endif // __dialog_sch_sheet_props__ diff --git a/eeschema/dialogs/dialog_sch_sheet_props_base.cpp b/eeschema/dialogs/dialog_sch_sheet_props_base.cpp new file mode 100644 index 00000000..f85225b1 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_sheet_props_base.cpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_sch_sheet_props_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_SCH_SHEET_PROPS_BASE::DIALOG_SCH_SHEET_PROPS_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( 500,150 ), wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bupperSizer; + bupperSizer = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer( 0, 6, 0, 0 ); + fgSizer1->AddGrowableCol( 1 ); + fgSizer1->SetFlexibleDirection( wxBOTH ); + fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("&File name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + fgSizer1->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textFileName->SetMaxLength( 0 ); + m_textFileName->SetMinSize( wxSize( 200,-1 ) ); + + fgSizer1->Add( m_textFileName, 5, wxEXPAND|wxTOP|wxBOTTOM, 3 ); + + + fgSizer1->Add( 0, 0, 1, wxALIGN_CENTER_HORIZONTAL|wxALL, 3 ); + + m_staticText2 = new wxStaticText( this, wxID_ANY, _("Si&ze:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + fgSizer1->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textFileNameSize = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textFileNameSize->SetMaxLength( 0 ); + fgSizer1->Add( m_textFileNameSize, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 3 ); + + m_staticFileNameSizeUnits = new wxStaticText( this, wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticFileNameSizeUnits->Wrap( -1 ); + fgSizer1->Add( m_staticFileNameSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticText4 = new wxStaticText( this, wxID_ANY, _("&Sheet name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + fgSizer1->Add( m_staticText4, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textSheetName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textSheetName->SetMaxLength( 0 ); + fgSizer1->Add( m_textSheetName, 5, wxEXPAND|wxTOP|wxBOTTOM, 3 ); + + + fgSizer1->Add( 0, 0, 1, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticText5 = new wxStaticText( this, wxID_ANY, _("&Size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + fgSizer1->Add( m_staticText5, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_textSheetNameSize = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textSheetNameSize->SetMaxLength( 0 ); + fgSizer1->Add( m_textSheetNameSize, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 3 ); + + m_staticSheetNameSizeUnits = new wxStaticText( this, wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticSheetNameSizeUnits->Wrap( -1 ); + fgSizer1->Add( m_staticSheetNameSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 3 ); + + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + fgSizer1->Add( m_staticline2, 0, wxEXPAND|wxALL, 5 ); + + m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + fgSizer1->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_staticTextTimeStamp = new wxStaticText( this, wxID_ANY, _("Unique timestamp:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeStamp->Wrap( -1 ); + fgSizer1->Add( m_staticTextTimeStamp, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrlTimeStamp = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + fgSizer1->Add( m_textCtrlTimeStamp, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + + bupperSizer->Add( fgSizer1, 1, wxALL|wxEXPAND, 5 ); + + + mainSizer->Add( bupperSizer, 0, wxEXPAND, 5 ); + + + mainSizer->Add( 0, 0, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + mainSizer->Add( m_staticline1, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + mainSizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +DIALOG_SCH_SHEET_PROPS_BASE::~DIALOG_SCH_SHEET_PROPS_BASE() +{ +} diff --git a/eeschema/dialogs/dialog_sch_sheet_props_base.h b/eeschema/dialogs/dialog_sch_sheet_props_base.h new file mode 100644 index 00000000..46a438a6 --- /dev/null +++ b/eeschema/dialogs/dialog_sch_sheet_props_base.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_SCH_SHEET_PROPS_BASE_H__ +#define __DIALOG_SCH_SHEET_PROPS_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_SCH_SHEET_PROPS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_SCH_SHEET_PROPS_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText1; + wxTextCtrl* m_textFileName; + wxStaticText* m_staticText2; + wxTextCtrl* m_textFileNameSize; + wxStaticText* m_staticFileNameSizeUnits; + wxStaticText* m_staticText4; + wxTextCtrl* m_textSheetName; + wxStaticText* m_staticText5; + wxTextCtrl* m_textSheetNameSize; + wxStaticText* m_staticSheetNameSizeUnits; + wxStaticLine* m_staticline2; + wxStaticLine* m_staticline3; + wxStaticText* m_staticTextTimeStamp; + wxTextCtrl* m_textCtrlTimeStamp; + wxStaticLine* m_staticline1; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + public: + + DIALOG_SCH_SHEET_PROPS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Schematic Sheet Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 519,187 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_SCH_SHEET_PROPS_BASE(); + +}; + +#endif //__DIALOG_SCH_SHEET_PROPS_BASE_H__ diff --git a/eeschema/dialogs/dialog_schematic_find.cpp b/eeschema/dialogs/dialog_schematic_find.cpp new file mode 100644 index 00000000..52996a5a --- /dev/null +++ b/eeschema/dialogs/dialog_schematic_find.cpp @@ -0,0 +1,284 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Wayne Stambaugh + * Copyright (C) 2010-2011 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 + */ + +/** + * @file dialog_schematic_find.cpp + * @brief Schematic find and replace dialog implementation. + */ + +#include + + +DEFINE_EVENT_TYPE( EVT_COMMAND_FIND_DRC_MARKER ) +DEFINE_EVENT_TYPE( EVT_COMMAND_FIND_COMPONENT_IN_LIB ) + + +DIALOG_SCH_FIND::DIALOG_SCH_FIND( wxWindow* aParent, wxFindReplaceData* aData, + const wxPoint& aPosition, const wxSize& aSize, int aStyle ) : + DIALOG_SCH_FIND_BASE( aParent, wxID_ANY, _( "Find" ), aPosition, aSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | aStyle ) +{ + SetData( aData ); + + wxASSERT_MSG( m_findReplaceData, wxT( "can't create find dialog without data" ) ); + + if( aStyle & wxFR_REPLACEDIALOG ) + { + SetTitle( _( "Find and Replace" ) ); + m_buttonReplace->Show( true ); + m_buttonReplaceAll->Show( true ); + m_staticReplace->Show( true ); + m_comboReplace->Show( true ); + m_checkReplaceReferences->Show( true ); + m_checkWildcardMatch->Show( false ); // Wildcard replace is not implemented. + } + + int flags = m_findReplaceData->GetFlags(); + m_radioForward->SetValue( flags & wxFR_DOWN ); + m_radioBackward->SetValue( ( flags & wxFR_DOWN ) == 0 ); + m_checkMatchCase->SetValue( flags & wxFR_MATCHCASE ); + m_checkWholeWord->SetValue( flags & wxFR_WHOLEWORD ); + m_checkNoWarpCursor->SetValue( flags & FR_NO_WARP_CURSOR ); + + /* Whole word and wild card searches are mutually exclusive. */ + if( !( flags & wxFR_WHOLEWORD ) ) + m_checkWildcardMatch->SetValue( flags & FR_MATCH_WILDCARD ); + + m_checkAllFields->SetValue( flags & FR_SEARCH_ALL_FIELDS ); + m_checkReplaceReferences->SetValue( flags & FR_REPLACE_REFERENCES ); + m_checkAllPins->SetValue( flags & FR_SEARCH_ALL_PINS ); + m_checkWrap->SetValue( flags & FR_SEARCH_WRAP ); + m_checkCurrentSheetOnly->SetValue( flags & FR_CURRENT_SHEET_ONLY ); + + m_buttonFind->SetDefault(); + m_comboFind->SetFocus(); + SetPosition( aPosition ); + + // Adjust the height of the dialog to prevent controls from being hidden when + // switching between the find and find/replace modes of the dialog. This ignores + // the users preferred height if any of the controls would be hidden. + GetSizer()->SetSizeHints( this ); + wxSize size = aSize; + + if( aSize != wxDefaultSize ) + { + wxSize bestSize = GetBestSize(); + + if( size.GetHeight() != bestSize.GetHeight() ) + size.SetHeight( bestSize.GetHeight() ); + } + + SetSize( size ); + + GetSizer()->Fit( this ); // Needed on Ubuntu/Unity to display the dialog +} + + +void DIALOG_SCH_FIND::OnClose( wxCloseEvent& aEvent ) +{ + SendEvent( wxEVT_COMMAND_FIND_CLOSE ); +} + + +void DIALOG_SCH_FIND::OnUpdateFindUI( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( !m_comboFind->GetValue().empty() ); +} + + +void DIALOG_SCH_FIND::OnUpdateReplaceUI( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( HasFlag( wxFR_REPLACEDIALOG ) && !m_comboFind->GetValue().empty() && + (m_findReplaceData->GetFlags() & FR_REPLACE_ITEM_FOUND) ); +} + + +void DIALOG_SCH_FIND::OnUpdateWholeWordUI( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( !m_checkWildcardMatch->GetValue() ); +} + + +void DIALOG_SCH_FIND::OnUpdateWildcardUI( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( !m_checkWholeWord->GetValue() ); +} + + +void DIALOG_SCH_FIND::OnFind( wxCommandEvent& aEvent ) +{ + int index = m_comboFind->FindString( m_comboFind->GetValue(), true ); + + if( index == wxNOT_FOUND ) + { + m_comboFind->Insert( m_comboFind->GetValue(), 0 ); + } + else if( index != 0 ) + { + /* Move the search string to the top of the list if it isn't already there. */ + wxString tmp = m_comboFind->GetValue(); + m_comboFind->Delete( index ); + m_comboFind->Insert( tmp, 0 ); + m_comboFind->SetSelection( 0 ); + } + + SendEvent( wxEVT_COMMAND_FIND ); +} + + +void DIALOG_SCH_FIND::OnReplace( wxCommandEvent& aEvent ) +{ + int index = m_comboReplace->FindString( m_comboReplace->GetValue(), true ); + + if( index == wxNOT_FOUND ) + { + m_comboReplace->Insert( m_comboReplace->GetValue(), 0 ); + } + else if( index != 0 ) + { + /* Move the search string to the top of the list if it isn't already there. */ + wxString tmp = m_comboReplace->GetValue(); + m_comboReplace->Delete( index ); + m_comboReplace->Insert( tmp, 0 ); + m_comboReplace->SetSelection( 0 ); + } + + if( aEvent.GetId() == wxID_REPLACE ) + SendEvent( wxEVT_COMMAND_FIND_REPLACE ); + else if( aEvent.GetId() == wxID_REPLACE_ALL ) + SendEvent( wxEVT_COMMAND_FIND_REPLACE_ALL ); +} + + +void DIALOG_SCH_FIND::OnCancel( wxCommandEvent& aEvent ) +{ + SendEvent( wxEVT_COMMAND_FIND_CLOSE ); + Show( false ); +} + + +void DIALOG_SCH_FIND::SendEvent( const wxEventType& aEventType ) +{ + wxFindDialogEvent event( aEventType, GetId() ); + event.SetEventObject( this ); + event.SetFindString( m_comboFind->GetValue() ); + + int flags = 0; + + if ( HasFlag( wxFR_REPLACEDIALOG ) ) + { + event.SetReplaceString( m_comboReplace->GetValue() ); + flags |= FR_SEARCH_REPLACE; + } + + if( m_checkReplaceReferences->GetValue() ) + flags |= FR_REPLACE_REFERENCES; + + if( m_radioForward->GetValue() ) + flags |= wxFR_DOWN; + + if( m_checkMatchCase->GetValue() ) + flags |= wxFR_MATCHCASE; + + if( m_checkWholeWord->GetValue() ) + flags |= wxFR_WHOLEWORD; + + if( m_checkWildcardMatch->IsShown() && m_checkWildcardMatch->GetValue() ) + flags |= FR_MATCH_WILDCARD; + + if( m_checkAllFields->GetValue() ) + flags |= FR_SEARCH_ALL_FIELDS; + + if( m_checkAllPins->GetValue() ) + flags |= FR_SEARCH_ALL_PINS; + + if( m_checkWrap->GetValue() ) + flags |= FR_SEARCH_WRAP; + + if( m_checkCurrentSheetOnly->GetValue() ) + flags |= FR_CURRENT_SHEET_ONLY; + + if( m_checkNoWarpCursor->GetValue() ) + flags |= FR_NO_WARP_CURSOR; + + m_findReplaceData->SetFindString( event.GetFindString() ); + + if( HasFlag( wxFR_REPLACEDIALOG ) + && ( event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE + || event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL ) ) + { + m_findReplaceData->SetReplaceString( event.GetReplaceString() ); + } + + event.SetFlags( flags ); + + m_findReplaceData->SetFlags( event.GetFlags() ); + + // when we are no using the find/replace (just find) + // FR_REPLACE_REFERENCES flag bit is always set to 1 in event flags + // but not set in m_findReplaceData + if ( ! HasFlag( wxFR_REPLACEDIALOG ) ) + { + flags |= FR_REPLACE_REFERENCES; + event.SetFlags( flags ); + } + + if( !GetEventHandler()->ProcessEvent( event ) ) + { + GetParent()->GetEventHandler()->ProcessEvent( event ); + } + + if( event.GetFlags() != flags ) + m_findReplaceData->SetFlags( event.GetFlags() ); +} + + +wxArrayString DIALOG_SCH_FIND::GetFindEntries() const +{ + return m_comboFind->GetStrings(); +} + + +void DIALOG_SCH_FIND::SetFindEntries( const wxArrayString& aEntries ) +{ + m_comboFind->Append( aEntries ); + + if( m_comboFind->GetCount() ) + { + m_comboFind->SetSelection( 0 ); + m_comboFind->SelectAll(); + } +} + + +void DIALOG_SCH_FIND::SetReplaceEntries( const wxArrayString& aEntries ) +{ + m_comboReplace->Append( aEntries ); + + if( m_comboReplace->GetCount() ) + { + m_comboReplace->SetSelection( 0 ); + m_comboFind->SelectAll(); + } +} diff --git a/eeschema/dialogs/dialog_schematic_find.h b/eeschema/dialogs/dialog_schematic_find.h new file mode 100644 index 00000000..054cf011 --- /dev/null +++ b/eeschema/dialogs/dialog_schematic_find.h @@ -0,0 +1,201 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Wayne Stambaugh + * Copyright (C) 2010-2011 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 + */ + +/** + * @file + * + * Subclass of DIALOG_SCH_FIND_BASE, which is generated by wxFormBuilder. + * + * This dialog is used to define the search criteria used to search for items + * in the current schematic. What is searched depends on the schematic item + * type. Check the Matches() method for each item derived from SCH_ITEM() to + * find out how matching is performed against that item. + */ + +#ifndef __dialog_schematic_find__ +#define __dialog_schematic_find__ + +#include "dialog_schematic_find_base.h" + +#include // Use the wxFindReplaceDialog events, data, and enums. + + +/** + * Define schematic specific find and replace dialog flags based on the enum entries + * in wxFindReplaceFlags. These flags are intended to be used as bit masks in the + * wxFindReplaceData::m_Flags member variable. The variable is defined as a wxUint32. + */ +enum SchematicFindReplaceFlags +{ + // The last wxFindReplaceFlag enum is wxFR_MATCHCASE = 0x4. + + /// Search the current sheet only. + FR_CURRENT_SHEET_ONLY = wxFR_MATCHCASE << 1, + + /// Search all fields in component, not just the value and reference fields. + FR_SEARCH_ALL_FIELDS = wxFR_MATCHCASE << 2, + + /// Search texts (name and number (a 4 letters text) )in pins. + FR_SEARCH_ALL_PINS = wxFR_MATCHCASE << 3, + + /// Perform search using simple wild card matching (* & ?). + FR_MATCH_WILDCARD = wxFR_MATCHCASE << 4, + + /// Wrap around the beginning or end of search list. + FR_SEARCH_WRAP = wxFR_MATCHCASE << 5, + + /// Don't warp cursor to found item until the dialog is closed. + FR_NO_WARP_CURSOR = wxFR_MATCHCASE << 6, + + /// Perform a search for a item that has replaceable text. + FR_SEARCH_REPLACE = wxFR_MATCHCASE << 7, + + /// Used by the search event handler to let the dialog know that a replaceable + /// item has been found. + FR_REPLACE_ITEM_FOUND = wxFR_MATCHCASE << 8, + + /// Used by replace to ignore the component reference designator field. + FR_REPLACE_REFERENCES = wxFR_MATCHCASE << 9 +}; + + +/** + * Definition FR_MASK_NON_COMPARE_FLAGS + * is used to mask find/replace flag bits that do not effect the search results. + */ +#define FR_MASK_NON_COMPARE_FLAGS ~( wxFR_DOWN | FR_SEARCH_WRAP | FR_NO_WARP_CURSOR | \ + FR_REPLACE_ITEM_FOUND ) + + +/** + * Class SCH_FIND_REPLACE_DATA + * adds missing useful comparison and assignment operators to the wxFindReplaceData object. + */ +class SCH_FIND_REPLACE_DATA : public wxFindReplaceData +{ +public: + + SCH_FIND_REPLACE_DATA& operator =( SCH_FIND_REPLACE_DATA& aFindReplaceData ) + { + if( this == &aFindReplaceData ) + return *this; + + SetFlags( aFindReplaceData.GetFlags() ); + SetFindString( aFindReplaceData.GetFindString() ); + SetReplaceString( aFindReplaceData.GetReplaceString() ); + + return *this; + } + + bool operator ==( SCH_FIND_REPLACE_DATA& aFindReplaceData ) + { + return ( (GetFlags() == aFindReplaceData.GetFlags()) + && (GetFindString() == aFindReplaceData.GetFindString()) + && (GetReplaceString() == aFindReplaceData.GetReplaceString()) ); + } + + bool operator !=( SCH_FIND_REPLACE_DATA& aFindReplaceData ) + { + return !( *this == aFindReplaceData ); + } + + + /** + * Function ChangesCompare + * tests \a aFindReplaceData to see if it would result in a change in the search string + * comparison results. + * + * @param aFindReplaceData A reference to a #SCH_FIND_REPLACE_DATA object to compare + * against. + * @return True if \a aFindReplaceData would result in a search and/or replace change, + * otherwise false. + */ + bool ChangesCompare( const SCH_FIND_REPLACE_DATA& aFindReplaceData ) + { + return ( (GetFindString() != aFindReplaceData.GetFindString()) + || (GetCompareFlags() != aFindReplaceData.GetCompareFlags()) ); + } + + bool IsReplacing() const { return (GetFlags() & FR_SEARCH_REPLACE) != 0; } + bool IsWrapping() const { return (GetFlags() & FR_SEARCH_WRAP) != 0; } + +private: + /** + * Function GetSearchFlags + * @return The flags that only effect the search result. + */ + wxUint32 GetCompareFlags() const { return GetFlags() & FR_MASK_NON_COMPARE_FLAGS; } +}; + + +/** Implementing DIALOG_SCH_FIND_BASE */ +class DIALOG_SCH_FIND : public DIALOG_SCH_FIND_BASE +{ +protected: + // Handlers for DIALOG_SCH_FIND_BASE events. + void OnClose( wxCloseEvent& aEvent ); + void OnUpdateFindUI( wxUpdateUIEvent& aEvent ); + void OnUpdateReplaceUI( wxUpdateUIEvent& aEvent ); + void OnUpdateWholeWordUI( wxUpdateUIEvent& aEvent ); + void OnUpdateWildcardUI( wxUpdateUIEvent& aEvent ); + + void OnFind( wxCommandEvent& aEvent ); + void OnReplace( wxCommandEvent& aEvent ); + void OnCancel( wxCommandEvent& aEvent ); + + void SendEvent( const wxEventType& aEventType ); + + wxFindReplaceData *m_findReplaceData; + + DECLARE_NO_COPY_CLASS( DIALOG_SCH_FIND ) + +public: + DIALOG_SCH_FIND( wxWindow* aParent, wxFindReplaceData* aData, + const wxPoint& aPosition = wxDefaultPosition, + const wxSize& aSize = wxDefaultSize, int aStyle = 0 ); + + const wxFindReplaceData *GetData() const { return m_findReplaceData; } + void SetData(wxFindReplaceData *aData) { m_findReplaceData = aData; } + + void SetFindEntries( const wxArrayString& aEntries ); + wxArrayString GetFindEntries() const; + + void SetReplaceEntries( const wxArrayString& aEntries ); + wxArrayString GetReplaceEntries() const { return m_comboReplace->GetStrings(); } +}; + + +BEGIN_DECLARE_EVENT_TYPES() + DECLARE_LOCAL_EVENT_TYPE( EVT_COMMAND_FIND_DRC_MARKER, wxID_ANY ) + DECLARE_LOCAL_EVENT_TYPE( EVT_COMMAND_FIND_COMPONENT_IN_LIB, wxID_ANY ) +END_DECLARE_EVENT_TYPES() + + +#define EVT_FIND_DRC_MARKER( id, fn ) \ + wx__DECLARE_EVT1( EVT_COMMAND_FIND_DRC_MARKER, id, wxFindDialogEventHandler( fn ) ) + +#define EVT_FIND_COMPONENT_IN_LIB( id, fn ) \ + wx__DECLARE_EVT1( EVT_COMMAND_FIND_COMPONENT_IN_LIB, id, wxFindDialogEventHandler( fn ) ) + +#endif // __dialog_schematic_find__ diff --git a/eeschema/dialogs/dialog_schematic_find_base.cpp b/eeschema/dialogs/dialog_schematic_find_base.cpp new file mode 100644 index 00000000..59f78e2e --- /dev/null +++ b/eeschema/dialogs/dialog_schematic_find_base.cpp @@ -0,0 +1,169 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_schematic_find_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_SCH_FIND_BASE::DIALOG_SCH_FIND_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( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* leftSizer; + leftSizer = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* leftGridSizer; + leftGridSizer = new wxFlexGridSizer( 3, 2, 3, 3 ); + leftGridSizer->AddGrowableCol( 1 ); + leftGridSizer->SetFlexibleDirection( wxBOTH ); + leftGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("&Search for:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + leftGridSizer->Add( m_staticText1, 0, wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_comboFind = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN ); + m_comboFind->SetToolTip( _("Text with optional wildcards") ); + m_comboFind->SetMinSize( wxSize( 125,-1 ) ); + + leftGridSizer->Add( m_comboFind, 1, wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_staticReplace = new wxStaticText( this, wxID_ANY, _("Replace &with:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticReplace->Wrap( -1 ); + m_staticReplace->Hide(); + + leftGridSizer->Add( m_staticReplace, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_comboReplace = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + m_comboReplace->Hide(); + + leftGridSizer->Add( m_comboReplace, 0, wxALL|wxEXPAND, 5 ); + + m_staticDirection = new wxStaticText( this, wxID_ANY, _("Direction:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticDirection->Wrap( -1 ); + m_staticDirection->Hide(); + + leftGridSizer->Add( m_staticDirection, 0, 0, 5 ); + + wxBoxSizer* directionSizer; + directionSizer = new wxBoxSizer( wxVERTICAL ); + + m_radioForward = new wxRadioButton( this, wxID_ANY, _("F&orward"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + m_radioForward->Hide(); + + directionSizer->Add( m_radioForward, 0, wxALL, 3 ); + + m_radioBackward = new wxRadioButton( this, wxID_ANY, _("&Backward"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBackward->Hide(); + + directionSizer->Add( m_radioBackward, 0, wxALL, 3 ); + + + leftGridSizer->Add( directionSizer, 1, wxEXPAND, 5 ); + + + leftSizer->Add( leftGridSizer, 1, wxALL|wxEXPAND, 6 ); + + m_checkWholeWord = new wxCheckBox( this, wxID_ANY, _("Match whole wor&d"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkWholeWord->SetValue(true); + leftSizer->Add( m_checkWholeWord, 0, wxALL, 6 ); + + m_checkMatchCase = new wxCheckBox( this, wxID_ANY, _("&Match case"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkMatchCase, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkWildcardMatch = new wxCheckBox( this, wxID_ANY, _("Search &using simple wildcard matching"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkWildcardMatch, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkWrap = new wxCheckBox( this, wxID_ANY, _("Wrap around &end of search list"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkWrap->SetValue(true); + leftSizer->Add( m_checkWrap, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkAllFields = new wxCheckBox( this, wxID_ANY, _("Search all com&ponent fields"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkAllFields, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkAllPins = new wxCheckBox( this, wxID_ANY, _("Search all pin &names and numbers"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkAllPins, 0, wxBOTTOM|wxRIGHT|wxLEFT, 6 ); + + m_checkCurrentSheetOnly = new wxCheckBox( this, wxID_ANY, _("Search the current &sheet onl&y"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkCurrentSheetOnly, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkReplaceReferences = new wxCheckBox( this, wxID_ANY, _("Replace componen&t reference designators"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkReplaceReferences->Hide(); + + leftSizer->Add( m_checkReplaceReferences, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + m_checkNoWarpCursor = new wxCheckBox( this, wxID_ANY, _("D&o not warp cursor to found item"), wxDefaultPosition, wxDefaultSize, 0 ); + leftSizer->Add( m_checkNoWarpCursor, 0, wxBOTTOM|wxLEFT|wxRIGHT, 6 ); + + + mainSizer->Add( leftSizer, 1, wxALL|wxEXPAND, 6 ); + + wxBoxSizer* rightSizer; + rightSizer = new wxBoxSizer( wxVERTICAL ); + + m_buttonFind = new wxButton( this, wxID_FIND, _("&Find"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonFind->SetDefault(); + rightSizer->Add( m_buttonFind, 0, wxALL|wxEXPAND, 6 ); + + m_buttonReplace = new wxButton( this, wxID_REPLACE, _("&Replace"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonReplace->Hide(); + + rightSizer->Add( m_buttonReplace, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_buttonReplaceAll = new wxButton( this, wxID_REPLACE_ALL, _("Replace &All"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonReplaceAll->Hide(); + + rightSizer->Add( m_buttonReplaceAll, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 6 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); + rightSizer->Add( m_buttonCancel, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND, 6 ); + + + mainSizer->Add( rightSizer, 0, wxALL|wxEXPAND, 6 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + mainSizer->Fit( this ); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_SCH_FIND_BASE::OnClose ) ); + m_comboFind->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this ); + m_comboReplace->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this ); + m_checkWholeWord->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateWholeWordUI ), NULL, this ); + m_checkWildcardMatch->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateWildcardUI ), NULL, this ); + m_buttonFind->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnFind ), NULL, this ); + m_buttonFind->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateFindUI ), NULL, this ); + m_buttonReplace->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this ); + m_buttonReplace->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this ); + m_buttonReplaceAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this ); + m_buttonReplaceAll->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this ); + m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnCancel ), NULL, this ); +} + +DIALOG_SCH_FIND_BASE::~DIALOG_SCH_FIND_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_SCH_FIND_BASE::OnClose ) ); + m_comboFind->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this ); + m_comboReplace->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateDrcUI ), NULL, this ); + m_checkWholeWord->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateWholeWordUI ), NULL, this ); + m_checkWildcardMatch->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateWildcardUI ), NULL, this ); + m_buttonFind->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnFind ), NULL, this ); + m_buttonFind->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateFindUI ), NULL, this ); + m_buttonReplace->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this ); + m_buttonReplace->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this ); + m_buttonReplaceAll->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnReplace ), NULL, this ); + m_buttonReplaceAll->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SCH_FIND_BASE::OnUpdateReplaceUI ), NULL, this ); + m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SCH_FIND_BASE::OnCancel ), NULL, this ); + +} diff --git a/eeschema/dialogs/dialog_schematic_find_base.fbp b/eeschema/dialogs/dialog_schematic_find_base.fbp new file mode 100644 index 00000000..5a759742 --- /dev/null +++ b/eeschema/dialogs/dialog_schematic_find_base.fbp @@ -0,0 +1,1901 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_schematic_find_base + 1000 + none + 1 + dialog_sch_find + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_SCH_FIND_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Find + + + + + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxHORIZONTAL + none + + 6 + wxALL|wxEXPAND + 1 + + + leftSizer + wxVERTICAL + none + + 6 + wxALL|wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 3 + + leftGridSizer + wxFLEX_GROWMODE_SPECIFIED + none + 3 + 3 + + 6 + wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Search for: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxEXPAND|wxLEFT|wxRIGHT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 125,-1 + 1 + m_comboFind + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_DROPDOWN + + 0 + Text with optional wildcards + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnUpdateDrcUI + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + Replace &with: + + 0 + + + 0 + + 1 + m_staticReplace + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboReplace + 1 + + + protected + 1 + + Resizable + -1 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnUpdateDrcUI + + + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + Direction: + + 0 + + + 0 + + 1 + m_staticDirection + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + directionSizer + wxVERTICAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + F&orward + + 0 + + + 0 + + 1 + m_radioForward + 1 + + + protected + 1 + + Resizable + 1 + + wxRB_GROUP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + &Backward + + 0 + + + 0 + + 1 + m_radioBackward + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Match whole wor&d + + 0 + + + 0 + + 1 + m_checkWholeWord + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnUpdateWholeWordUI + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + &Match case + + 0 + + + 0 + + 1 + m_checkMatchCase + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Search &using simple wildcard matching + + 0 + + + 0 + + 1 + m_checkWildcardMatch + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnUpdateWildcardUI + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Wrap around &end of search list + + 0 + + + 0 + + 1 + m_checkWrap + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Search all com&ponent fields + + 0 + + + 0 + + 1 + m_checkAllFields + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Search all pin &names and numbers + + 0 + + + 0 + + 1 + m_checkAllPins + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Search the current &sheet onl&y + + 0 + + + 0 + + 1 + m_checkCurrentSheetOnly + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + Replace componen&t reference designators + + 0 + + + 0 + + 1 + m_checkReplaceReferences + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + D&o not warp cursor to found item + + 0 + + + 0 + + 1 + m_checkNoWarpCursor + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + wxALL|wxEXPAND + 0 + + + rightSizer + wxVERTICAL + none + + 6 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_FIND + &Find + + 0 + + + 0 + + 1 + m_buttonFind + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnFind + + + + + + + + + + + + + + + + + + + + + + + OnUpdateFindUI + + + + 6 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_REPLACE + &Replace + + 0 + + + 0 + + 1 + m_buttonReplace + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnReplace + + + + + + + + + + + + + + + + + + + + + + + OnUpdateReplaceUI + + + + 6 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_REPLACE_ALL + Replace &All + + 0 + + + 0 + + 1 + m_buttonReplaceAll + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnReplace + + + + + + + + + + + + + + + + + + + + + + + OnUpdateReplaceUI + + + + 6 + wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Close + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_schematic_find_base.h b/eeschema/dialogs/dialog_schematic_find_base.h new file mode 100644 index 00000000..9fe0de45 --- /dev/null +++ b/eeschema/dialogs/dialog_schematic_find_base.h @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Mar 9 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_SCHEMATIC_FIND_BASE_H__ +#define __DIALOG_SCHEMATIC_FIND_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_SCH_FIND_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_SCH_FIND_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText1; + wxComboBox* m_comboFind; + wxStaticText* m_staticReplace; + wxComboBox* m_comboReplace; + wxStaticText* m_staticDirection; + wxRadioButton* m_radioForward; + wxRadioButton* m_radioBackward; + wxCheckBox* m_checkWholeWord; + wxCheckBox* m_checkMatchCase; + wxCheckBox* m_checkWildcardMatch; + wxCheckBox* m_checkWrap; + wxCheckBox* m_checkAllFields; + wxCheckBox* m_checkAllPins; + wxCheckBox* m_checkCurrentSheetOnly; + wxCheckBox* m_checkReplaceReferences; + wxCheckBox* m_checkNoWarpCursor; + wxButton* m_buttonFind; + wxButton* m_buttonReplace; + wxButton* m_buttonReplaceAll; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnUpdateDrcUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnUpdateWholeWordUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnUpdateWildcardUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnFind( wxCommandEvent& event ) { event.Skip(); } + virtual void OnUpdateFindUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnReplace( wxCommandEvent& event ) { event.Skip(); } + virtual void OnUpdateReplaceUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_SCH_FIND_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Find"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_SCH_FIND_BASE(); + +}; + +#endif //__DIALOG_SCHEMATIC_FIND_BASE_H__ diff --git a/eeschema/edit_bitmap.cpp b/eeschema/edit_bitmap.cpp new file mode 100644 index 00000000..2cdc8920 --- /dev/null +++ b/eeschema/edit_bitmap.cpp @@ -0,0 +1,199 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 jean-pierre.charras + * Copyright (C) 2012 KiCad Developers, see change_log.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 + */ + +/** + * @file edit_bitmap.cpp + */ + +#include +#include + +#include +#include +#include + + +static void abortMoveBitmap( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + SCH_BITMAP* item = (SCH_BITMAP*) screen->GetCurItem(); + SCH_EDIT_FRAME* parent = (SCH_EDIT_FRAME*) aPanel->GetParent(); + + parent->SetRepeatItem( NULL ); + + if( item == NULL ) /* no current item */ + return; + + if( item->IsNew() ) + { + delete item; + item = NULL; + } + else // Move command on an existing text item, restore the data of the original. + { + item->ClearFlags(); + + SCH_BITMAP * olditem = (SCH_BITMAP*) parent->GetUndoItem(); + + wxCHECK_RET( olditem != NULL && item->Type() == olditem->Type() && + item->Type() == SCH_BITMAP_T, + wxT( "Cannot restore undefined last text item." ) ); + + // Never delete existing item, because it can be referenced by an undo/redo command + // Just restore its data + item->SwapData( olditem ); + parent->SetUndoItem( NULL ); + } + + screen->SetCurItem( item ); + aPanel->Refresh(); +} + +static void moveBitmap( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + SCH_BITMAP* image = (SCH_BITMAP*) screen->GetCurItem(); + + if( aErase ) + { + // Erase the current bitmap at its current position. + // Note also items flagged IS_MOVING are not drawn, + // and if image is new, it is not yet il draw list + // so image is erased from screen + EDA_RECT dirty = image->GetBoundingBox(); + dirty.Inflate( 4 ); // Give a margin + aPanel->SetMouseCapture( NULL, NULL ); // Avoid loop in redraw panel + + STATUS_FLAGS flgs = image->GetFlags(); + image->ClearFlags(); + aPanel->RefreshDrawingRect( dirty ); + image->SetFlags( flgs ); + aPanel->SetMouseCapture( moveBitmap, abortMoveBitmap ); + } + + // Draw the bitmap at it's new position. + image->SetPosition( aPanel->GetParent()->GetCrossHairPosition() ); + image->Draw( aPanel, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); +} + + +SCH_BITMAP* SCH_EDIT_FRAME::CreateNewImage( wxDC* aDC ) +{ + wxFileDialog fileDlg( this, _( "Choose Image" ), wxEmptyString, wxEmptyString, + _( "Image Files " ) + wxImage::GetImageExtWildcard(), + wxFD_OPEN ); + int diag = fileDlg.ShowModal(); + + if( diag != wxID_OK ) + return NULL; + + wxString fullFilename = fileDlg.GetPath(); + + if( !wxFileExists( fullFilename ) ) + { + wxMessageBox( _( "Couldn't load image from <%s>" ), GetChars( fullFilename ) ); + return NULL; + } + + wxPoint pos = GetCrossHairPosition(); + + SCH_BITMAP* image = new SCH_BITMAP( pos ); + + if( !image->ReadImageFile( fullFilename ) ) + { + wxMessageBox( _( "Couldn't load image from <%s>" ), GetChars( fullFilename ) ); + delete image; + return NULL; + } + + + image->SetFlags( IS_NEW | IS_MOVED ); + image->Draw( m_canvas, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + + m_canvas->SetMouseCapture( moveBitmap, abortMoveBitmap ); + GetScreen()->SetCurItem( image ); + + OnModify(); + return image; +} + +void SCH_EDIT_FRAME::MoveImage( SCH_BITMAP* aImageItem, wxDC* aDC ) +{ + aImageItem->SetFlags( IS_MOVED ); + + m_canvas->SetMouseCapture( moveBitmap, abortMoveBitmap ); + GetScreen()->SetCurItem( aImageItem ); + SetRepeatItem( NULL ); + + SetUndoItem( aImageItem ); + + m_canvas->CrossHairOff( aDC ); + SetCrossHairPosition( aImageItem->GetPosition() ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->CrossHairOn( aDC ); + + OnModify(); +} + +void SCH_EDIT_FRAME::RotateImage( SCH_BITMAP* aItem ) +{ + if( aItem->GetFlags( ) == 0 ) + SaveCopyInUndoList( aItem, UR_ROTATED, aItem->GetPosition() ); + + aItem->Rotate( aItem->GetPosition() ); + OnModify(); + m_canvas->Refresh(); +} + +void SCH_EDIT_FRAME::MirrorImage( SCH_BITMAP* aItem, bool Is_X_axis ) +{ + if( aItem->GetFlags( ) == 0 ) + SaveCopyInUndoList( aItem, UR_CHANGED ); + + if( Is_X_axis ) + aItem->MirrorX( aItem->GetPosition().y ); + else + aItem->MirrorY( aItem->GetPosition().x ); + + OnModify(); + m_canvas->Refresh(); +} + +void SCH_EDIT_FRAME::EditImage( SCH_BITMAP* aItem ) +{ + // TODO: change image scale or more + DIALOG_IMAGE_EDITOR dlg( this, aItem->m_Image ); + if( dlg.ShowModal() != wxID_OK ) + return; + + // save old image in undo list if not already in edit + // or the image to be edited is part of a block + if( aItem->GetFlags() == 0 || + GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + SaveCopyInUndoList( aItem, UR_CHANGED ); + + dlg.TransfertToImage(aItem->m_Image); + OnModify(); + m_canvas->Refresh(); +} diff --git a/eeschema/edit_component_in_schematic.cpp b/eeschema/edit_component_in_schematic.cpp new file mode 100644 index 00000000..200bf270 --- /dev/null +++ b/eeschema/edit_component_in_schematic.cpp @@ -0,0 +1,117 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2016 Wayne Stambaugh + * Copyright (C) 2004-2013 KiCad Developers, see change_log.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 + */ + +/** + * @file edit_component_in_schematic.cpp + * @brief Schematic component editing code. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField ) +{ + wxCHECK_RET( aField != NULL && aField->Type() == SCH_FIELD_T, + wxT( "Cannot edit invalid schematic field." ) ); + + SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent(); + + wxCHECK_RET( component != NULL && component->Type() == SCH_COMPONENT_T, + wxT( "Invalid schematic field parent item." ) ); + + LIB_PART* part = Prj().SchLibs()->FindLibPart( component->GetPartName() ); + + wxCHECK_RET( part, wxT( "Library part for component <" ) + + component->GetPartName() + wxT( "> could not be found." ) ); + + // Save old component in undo list if not already in edit, or moving. + if( aField->GetFlags() == 0 ) + SaveCopyInUndoList( component, UR_CHANGED ); + + // Don't use GetText() here. If the field is the reference designator and it's parent + // component has multiple parts, we don't want the part suffix added to the field. + m_canvas->SetIgnoreMouseEvents( true ); + + wxString title; + title.Printf( _( "Edit %s Field" ), GetChars( aField->GetName() ) ); + + DIALOG_SCH_EDIT_ONE_FIELD dlg( this, title, aField ); + + // The dialog may invoke a kiway player for footprint fields + // so we must use a quasimodal + if( dlg.ShowQuasiModal() != wxID_OK ) + { + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + return; + } + + dlg.UpdateField( aField, m_CurrentSheet ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + OnModify(); + + m_canvas->Refresh(); + + MSG_PANEL_ITEMS items; + component->SetCurrentSheetPath( &GetCurrentSheet() ); + component->GetMsgPanelInfo( items ); + SetMsgPanel( items ); +} + + +void SCH_EDIT_FRAME::RotateField( SCH_FIELD* aField, wxDC* aDC ) +{ + wxCHECK_RET( aField != NULL && aField->Type() == SCH_FIELD_T && !aField->GetText().IsEmpty(), + wxT( "Cannot rotate invalid schematic field." ) ); + + SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent(); + + // Save old component in undo list if not already in edit, or moving. + if( aField->GetFlags() == 0 ) + SaveCopyInUndoList( component, UR_CHANGED ); + + aField->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + + if( aField->GetOrientation() == TEXT_ORIENT_HORIZ ) + aField->SetOrientation( TEXT_ORIENT_VERT ); + else + aField->SetOrientation( TEXT_ORIENT_HORIZ ); + + aField->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + + OnModify(); +} diff --git a/eeschema/edit_label.cpp b/eeschema/edit_label.cpp new file mode 100644 index 00000000..2be1d87b --- /dev/null +++ b/eeschema/edit_label.cpp @@ -0,0 +1,320 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2013 KiCad Developers, see change_log.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 + */ + +/** + * @file edit_label.cpp + * @brief Label, global label and text creation and editing. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +static int lastGlobalLabelShape = (int) NET_INPUT; +static int lastTextOrientation = 0; +static bool lastTextBold = false; +static bool lastTextItalic = false; + + +void SCH_EDIT_FRAME::ChangeTextOrient( SCH_TEXT* aTextItem, wxDC* aDC ) +{ + wxCHECK_RET( (aTextItem != NULL) && aTextItem->CanIncrementLabel(), + wxT( "Invalid schematic text item." ) ); + + int orient = ( aTextItem->GetOrientation() + 1 ) & 3; + + // Save current text orientation in undo list if is not already in edit. + if( aTextItem->GetFlags() == 0 ) + SaveCopyInUndoList( aTextItem, UR_CHANGED ); + + m_canvas->CrossHairOff( aDC ); + aTextItem->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + aTextItem->SetOrientation( orient ); + OnModify(); + aTextItem->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + m_canvas->CrossHairOn( aDC ); +} + + +SCH_TEXT* SCH_EDIT_FRAME::CreateNewText( wxDC* aDC, int aType ) +{ + SCH_TEXT* textItem = NULL; + + SetRepeatItem( NULL ); + + switch( aType ) + { + case LAYER_NOTES: + textItem = new SCH_TEXT( GetCrossHairPosition() ); + break; + + case LAYER_LOCLABEL: + textItem = new SCH_LABEL( GetCrossHairPosition() ); + break; + + case LAYER_HIERLABEL: + textItem = new SCH_HIERLABEL( GetCrossHairPosition() ); + textItem->SetShape( lastGlobalLabelShape ); + break; + + case LAYER_GLOBLABEL: + textItem = new SCH_GLOBALLABEL( GetCrossHairPosition() ); + textItem->SetShape( lastGlobalLabelShape ); + break; + + default: + DisplayError( this, wxT( "SCH_EDIT_FRAME::CreateNewText() Internal error" ) ); + return NULL; + } + + textItem->SetBold( lastTextBold ); + textItem->SetItalic( lastTextItalic ); + textItem->SetOrientation( lastTextOrientation ); + textItem->SetSize( wxSize( GetDefaultTextSize(), GetDefaultTextSize() ) ); + textItem->SetFlags( IS_NEW | IS_MOVED ); + + EditSchematicText( textItem ); + + if( textItem->GetText().IsEmpty() ) + { + delete textItem; + return NULL; + } + + lastTextBold = textItem->IsBold(); + lastTextItalic = textItem->IsItalic(); + lastTextOrientation = textItem->GetOrientation(); + + if( ( textItem->Type() == SCH_GLOBAL_LABEL_T ) || + ( textItem->Type() == SCH_HIERARCHICAL_LABEL_T ) ) + { + lastGlobalLabelShape = textItem->GetShape(); + } + + // Prepare display to move the new item + textItem->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( (SCH_ITEM*) textItem, aDC ); + + return textItem; +} + + +/* + * OnConvertTextType is a command event handler to change a text type to an other one. + * The new text, label, hierarchical label, or global label is created from the old text + * The old text is deleted. + * A tricky case is when the 'old" text is being edited (i.e. moving) + * because we must create a new text, and prepare the undo/redo command data for this + * change and the current move/edit command + */ +void SCH_EDIT_FRAME::OnConvertTextType( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_TEXT* text = (SCH_TEXT*) screen->GetCurItem(); + + wxCHECK_RET( (text != NULL) && text->CanIncrementLabel(), + wxT( "Cannot convert text type." ) ); + + KICAD_T type; + + switch( aEvent.GetId() ) + { + case ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_LABEL: + type = SCH_LABEL_T; + break; + + case ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_GLABEL: + type = SCH_GLOBAL_LABEL_T; + break; + + case ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_HLABEL: + type = SCH_HIERARCHICAL_LABEL_T; + break; + + case ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT: + type = SCH_TEXT_T; + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Invalid text type command ID %d." ), + aEvent.GetId() ) ); + return; + } + + if( text->Type() == type ) + return; + + SCH_TEXT* newtext; + const wxPoint &position = text->GetPosition(); + const wxString &txt = text->GetText(); + + switch( type ) + { + case SCH_LABEL_T: + newtext = new SCH_LABEL( position, txt ); + break; + + case SCH_GLOBAL_LABEL_T: + newtext = new SCH_GLOBALLABEL( position, txt ); + break; + + case SCH_HIERARCHICAL_LABEL_T: + newtext = new SCH_HIERLABEL( position, txt ); + break; + + case SCH_TEXT_T: + newtext = new SCH_TEXT( position, txt ); + break; + + default: + newtext = NULL; + wxFAIL_MSG( wxString::Format( wxT( "Cannot convert text type to %d" ), type ) ); + return; + } + + /* Copy the old text item settings to the new one. Justifications are not copied because + * they are not used in labels. Justifications will be set to default value in the new + * text item type. + */ + newtext->SetFlags( text->GetFlags() ); + newtext->SetShape( text->GetShape() ); + newtext->SetOrientation( text->GetOrientation() ); + newtext->SetSize( text->GetSize() ); + newtext->SetThickness( text->GetThickness() ); + newtext->SetItalic( text->IsItalic() ); + newtext->SetBold( text->IsBold() ); + + /* Save the new text in undo list if the old text was not itself a "new created text" + * In this case, the old text is already in undo list as a deleted item. + * Of course if the old text was a "new created text" the new text will be + * put in undo list later, at the end of the current command (if not aborted) + */ + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + m_canvas->CrossHairOff( &dc ); // Erase schematic cursor + text->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + + // For an exiting item (i.e. already in list): + // replace the existing item by the new text in list + for( SCH_ITEM* item = screen->GetDrawItems(); item != NULL; item = item->Next() ) + { + if( item == text ) + { + screen->Remove( text ); + screen->Append( newtext ); + break; + } + } + + SetRepeatItem( NULL ); + OnModify(); + newtext->Draw( m_canvas, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + m_canvas->CrossHairOn( &dc ); // redraw schematic cursor + + // if the old item is the current schematic item, replace it by the new text: + if( screen->GetCurItem() == text ) + screen->SetCurItem( newtext ); + + if( text->IsNew() ) + { + // if the previous text is new, no undo command to prepare here + // just delete this previous text. + delete text; + return; + } + + // previous text is not new and we replace text by new text. + // So this is equivalent to delete text and add newtext + // If text if being currently edited (i.e. moved) + // we also save the initial copy of text, and prepare undo command for new text modifications. + // we must save it as modified text,if it is currently edited, then save as deleted text, + // and replace text with newtext + PICKED_ITEMS_LIST pickList; + ITEM_PICKER picker( text, UR_CHANGED ); + + if( text->GetFlags() ) + { + // text is being edited, save initial text for undo command + picker.SetLink( GetUndoItem() ); + pickList.PushItem( picker ); + + // the owner of undoItem is no more "this", it is now "picker": + SetUndoItem( NULL ); + + // save current newtext copy for undo/abort current command + SetUndoItem( newtext ); + } + + // Prepare undo command for delete old text + picker.SetStatus( UR_DELETED ); + picker.SetLink( NULL ); + pickList.PushItem( picker ); + + // Prepare undo command for new text + picker.SetStatus( UR_NEW ); + picker.SetItem(newtext); + pickList.PushItem( picker ); + + SaveCopyInUndoList( pickList, UR_UNSPECIFIED ); +} + + +/* Function to increment bus label members numbers, + * i.e. when a text is ending with a number, adds + * aIncrement to this number + */ +void IncrementLabelMember( wxString& name, int aIncrement ) +{ + int ii, nn; + long number = 0; + + ii = name.Len() - 1; nn = 0; + + if( !isdigit( name.GetChar( ii ) ) ) + return; + + while( (ii >= 0) && isdigit( name.GetChar( ii ) ) ) + { + ii--; nn++; + } + + ii++; /* digits are starting at ii position */ + wxString litt_number = name.Right( nn ); + + if( litt_number.ToLong( &number ) ) + { + number += aIncrement; + name.Remove( ii ); name << number; + } +} diff --git a/eeschema/eeredraw.cpp b/eeschema/eeredraw.cpp new file mode 100644 index 00000000..7f0899d3 --- /dev/null +++ b/eeschema/eeredraw.cpp @@ -0,0 +1,86 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2009-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file eeredraw.cpp + */ + +#include +#include +#include +#include +#include + + +void DrawDanglingSymbol( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& pos, EDA_COLOR_T Color ) +{ + BASE_SCREEN* screen = panel->GetScreen(); + + if( !screen->m_IsPrinting ) /* Draw but do not print the Dangling Symbol */ + { + GRRect( panel->GetClipBox(), DC, + pos.x - DANGLING_SYMBOL_SIZE, pos.y - DANGLING_SYMBOL_SIZE, + pos.x + DANGLING_SYMBOL_SIZE, pos.y + DANGLING_SYMBOL_SIZE, + 0, Color ); + } +} + + +/* + * Redraws only the active window which is assumed to be whole visible. + */ +void SCH_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg ) +{ + if( GetScreen() == NULL ) + return; + + m_canvas->DrawBackGround( DC ); + + GetScreen()->Draw( m_canvas, DC, GR_DEFAULT_DRAWMODE ); + + DrawWorkSheet( DC, GetScreen(), GetDefaultLineThickness(), IU_PER_MILS, + GetScreen()->GetFileName() ); + +#ifdef USE_WX_OVERLAY + if( IsShown() ) + { + m_overlay.Reset(); + wxDCOverlay overlaydc( m_overlay, (wxWindowDC*)DC ); + overlaydc.Clear(); + /* TODO: Investigate why toolbars are affected - to be searched in wxWidgets */ + m_mainToolBar->Refresh(); + m_drawToolBar->Refresh(); + m_optionsToolBar->Refresh(); + } +#endif + + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + m_canvas->DrawCrossHair( DC ); + + // Display the sheet filename, and the sheet path, for non root sheets + UpdateTitle(); +} diff --git a/eeschema/eeschema.cpp b/eeschema/eeschema.cpp new file mode 100644 index 00000000..cfc062ac --- /dev/null +++ b/eeschema/eeschema.cpp @@ -0,0 +1,242 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema.cpp + * @brief the main file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// The main sheet of the project +SCH_SHEET* g_RootSheet = NULL; + +// a transform matrix, to display components in lib editor +TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 ); + + +namespace SCH { + +static struct IFACE : public KIFACE_I +{ + // Of course all are virtual overloads, implementations of the KIFACE. + + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} + + bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ); + + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { + case FRAME_SCH: + { + SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent ); + + if( Kiface().IsSingle() ) + { + // only run this under single_top, not under a project manager. + CreateServer( frame, KICAD_SCH_PORT_SERVICE_NUMBER ); + } + return frame; + } + break; + + case FRAME_SCH_LIB_EDITOR: + { + LIB_EDIT_FRAME* frame = new LIB_EDIT_FRAME( aKiway, aParent ); + return frame; + } + break; + + + case FRAME_SCH_VIEWER: + case FRAME_SCH_VIEWER_MODAL: + { + LIB_VIEW_FRAME* frame = new LIB_VIEW_FRAME( aKiway, aParent, FRAME_T( aClassId ) ); + return frame; + } + break; + + default: + return NULL; + } + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + +} kiface( "eeschema", KIWAY::FACE_SCH ); + +} // namespace + +using namespace SCH; + +static PGM_BASE* process; + + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) +{ + process = aProgram; + return &kiface; +} + + +PGM_BASE& Pgm() +{ + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} + + +static EDA_COLOR_T s_layerColor[LAYERSCH_ID_COUNT]; + +EDA_COLOR_T GetLayerColor( LAYERSCH_ID aLayer ) +{ + wxASSERT( unsigned( aLayer ) < DIM( s_layerColor ) ); + return s_layerColor[aLayer]; +} + +void SetLayerColor( EDA_COLOR_T aColor, LAYERSCH_ID aLayer ) +{ + wxASSERT( unsigned( aLayer ) < DIM( s_layerColor ) ); + s_layerColor[aLayer] = aColor; +} + + +static PARAM_CFG_ARRAY& cfg_params() +{ + static PARAM_CFG_ARRAY ca; + + if( !ca.size() ) + { + // These are KIFACE specific, they need to be loaded once when the + // eeschema KIFACE comes in. + +#define CLR(x, y, z)\ + ca.push_back( new PARAM_CFG_SETCOLOR( true, wxT( x ), &s_layerColor[y], z ) ); + + CLR( "ColorWireEx", LAYER_WIRE, GREEN ) + CLR( "ColorBusEx", LAYER_BUS, BLUE ) + CLR( "ColorConnEx", LAYER_JUNCTION, GREEN ) + CLR( "ColorLLabelEx", LAYER_LOCLABEL, BLACK ) + CLR( "ColorHLabelEx", LAYER_HIERLABEL, BROWN ) + CLR( "ColorGLabelEx", LAYER_GLOBLABEL, RED ) + CLR( "ColorPinNumEx", LAYER_PINNUM, RED ) + CLR( "ColorPinNameEx", LAYER_PINNAM, CYAN ) + CLR( "ColorFieldEx", LAYER_FIELDS, MAGENTA ) + CLR( "ColorReferenceEx", LAYER_REFERENCEPART, CYAN ) + CLR( "ColorValueEx", LAYER_VALUEPART, CYAN ) + CLR( "ColorNoteEx", LAYER_NOTES, LIGHTBLUE ) + CLR( "ColorBodyEx", LAYER_DEVICE, RED ) + CLR( "ColorBodyBgEx", LAYER_DEVICE_BACKGROUND,LIGHTYELLOW ) + CLR( "ColorNetNameEx", LAYER_NETNAM, DARKGRAY ) + CLR( "ColorPinEx", LAYER_PIN, RED ) + CLR( "ColorSheetEx", LAYER_SHEET, MAGENTA ) + CLR( "ColorSheetFileNameEx", LAYER_SHEETFILENAME, BROWN ) + CLR( "ColorSheetNameEx", LAYER_SHEETNAME, CYAN ) + CLR( "ColorSheetLabelEx", LAYER_SHEETLABEL, BROWN ) + CLR( "ColorNoConnectEx", LAYER_NOCONNECT, BLUE ) + CLR( "ColorErcWEx", LAYER_ERC_WARN, GREEN ) + CLR( "ColorErcEEx", LAYER_ERC_ERR, RED ) + CLR( "ColorGridEx", LAYER_GRID, DARKGRAY ) + CLR( "ColorBgCanvasEx", LAYER_BACKGROUND, WHITE ) + } + + return ca; +} + + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) +{ + // This is process level, not project level, initialization of the DSO. + + // Do nothing in here pertinent to a project! + + start_common( aCtlBits ); + + // Give a default colour for all layers + // (actual color will be initialized by config) + for( LAYERSCH_ID ii = LAYER_FIRST; ii < LAYERSCH_ID_COUNT; ++ii ) + SetLayerColor( DARKGRAY, ii ); + + SetLayerColor( WHITE, LAYER_BACKGROUND ); + + // Must be called before creating the main frame in order to + // display the real hotkeys in menus or tool tips + ReadHotkeyConfig( SCH_EDIT_FRAME_NAME, g_Eeschema_Hokeys_Descr ); + + wxConfigLoadSetups( KifaceSettings(), cfg_params() ); + + return true; +} + + +void IFACE::OnKifaceEnd() +{ + wxConfigSaveSetups( KifaceSettings(), cfg_params() ); + end_common(); +} + diff --git a/eeschema/eeschema.icns b/eeschema/eeschema.icns new file mode 100644 index 00000000..ca5e9d27 Binary files /dev/null and b/eeschema/eeschema.icns differ diff --git a/eeschema/eeschema.rc b/eeschema/eeschema.rc new file mode 100644 index 00000000..6c12ddd8 --- /dev/null +++ b/eeschema/eeschema.rc @@ -0,0 +1,3 @@ +icon_eeschema ICON "../bitmaps_png/icons/icon_eeschema.ico" + +#include "wx/msw/wx.rc" diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp new file mode 100644 index 00000000..c2aeaeb4 --- /dev/null +++ b/eeschema/eeschema_config.cpp @@ -0,0 +1,810 @@ +/** + * @file eeschema_config.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2016 KiCad Developers, see CHANGELOG.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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#define FR_HISTORY_LIST_CNT 10 ///< Maximum number of find and replace strings. + + +static int s_defaultBusThickness = DEFAULTBUSTHICKNESS; + +int GetDefaultBusThickness() +{ + return s_defaultBusThickness; +} + + +void SetDefaultBusThickness( int aThickness) +{ + if( aThickness >= 1 ) + s_defaultBusThickness = aThickness; + else + s_defaultBusThickness = 1; +} + + +/// Default size for text (not only labels) +static int s_defaultTextSize = DEFAULT_SIZE_TEXT; + +int GetDefaultTextSize() +{ + return s_defaultTextSize; +} + + +void SetDefaultTextSize( int aTextSize ) +{ + s_defaultTextSize = aTextSize; +} + + +/* + * Default line (in Eeschema units) thickness used to draw/plot items having a + * default thickness line value (i.e. = 0 ). + */ +static int s_drawDefaultLineThickness = DEFAULTDRAWLINETHICKNESS; + + +int GetDefaultLineThickness() +{ + return s_drawDefaultLineThickness; +} + + +void SetDefaultLineThickness( int aThickness ) +{ + if( aThickness >=1 ) + s_drawDefaultLineThickness = aThickness; + else + s_drawDefaultLineThickness = 1; +} + + +// Color to draw selected items +EDA_COLOR_T GetItemSelectedColor() +{ + return BROWN; +} + + +// Color to draw items flagged invisible, in libedit (they are invisible +// in Eeschema +EDA_COLOR_T GetInvisibleItemColor() +{ + return DARKGRAY; +} + + +void LIB_EDIT_FRAME::InstallConfigFrame( wxCommandEvent& event ) +{ + // Identical to SCH_EDIT_FRAME::InstallConfigFrame() + + PROJECT* prj = &Prj(); + wxArrayString lib_names; + wxString lib_paths; + + try + { + PART_LIBS::LibNamesAndPaths( prj, false, &lib_paths, &lib_names ); + } + catch( const IO_ERROR& ioe ) + { + DBG(printf( "%s: %s\n", __func__, TO_UTF8( ioe.errorText ) );) + return; + } + + if( InvokeEeschemaConfig( this, &lib_paths, &lib_names ) ) + { + // save the [changed] settings. + PART_LIBS::LibNamesAndPaths( prj, true, &lib_paths, &lib_names ); + + // Force a reload of the PART_LIBS + prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL ); + prj->SetElem( PROJECT::ELEM_SCH_SEARCH_STACK, NULL ); + } +} + + +void LIB_EDIT_FRAME::OnColorConfig( wxCommandEvent& aEvent ) +{ + DIALOG_COLOR_CONFIG dlg( this ); + + dlg.ShowModal(); +} + + +void LIB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) +{ + int id = event.GetId(); + + switch( id ) + { + // Hotkey IDs + case ID_PREFERENCES_HOTKEY_SHOW_EDITOR: + InstallHotkeyFrame( this, g_Eeschema_Hokeys_Descr ); + break; + + case ID_PREFERENCES_HOTKEY_EXPORT_CONFIG: + ExportHotkeyConfigToFile( g_Eeschema_Hokeys_Descr, wxT( "eeschema" ) ); + break; + + case ID_PREFERENCES_HOTKEY_IMPORT_CONFIG: + ImportHotkeyConfigFromFile( g_Eeschema_Hokeys_Descr, wxT( "eeschema" ) ); + break; + + case ID_PREFERENCES_HOTKEY_SHOW_CURRENT_LIST: + // Display current hotkey list for LibEdit. + DisplayHotkeyList( this, g_Libedit_Hokeys_Descr ); + break; + + default: + DisplayError( this, wxT( "LIB_EDIT_FRAME::Process_Config error" ) ); + } +} + + +void SCH_EDIT_FRAME::OnColorConfig( wxCommandEvent& aEvent ) +{ + DIALOG_COLOR_CONFIG dlg( this ); + + dlg.ShowModal(); +} + + +void SCH_EDIT_FRAME::InstallConfigFrame( wxCommandEvent& event ) +{ + // Identical to LIB_EDIT_FRAME::InstallConfigFrame() + + PROJECT* prj = &Prj(); + wxArrayString lib_names; + wxString lib_paths; + + try + { + PART_LIBS::LibNamesAndPaths( prj, false, &lib_paths, &lib_names ); + } + catch( const IO_ERROR& ioe ) + { + DBG(printf( "%s: %s\n", __func__, TO_UTF8( ioe.errorText ) );) + return; + } + + if( InvokeEeschemaConfig( this, &lib_paths, &lib_names ) ) + { + // save the [changed] settings. + PART_LIBS::LibNamesAndPaths( prj, true, &lib_paths, &lib_names ); + +#if defined(DEBUG) + printf( "%s: lib_names:\n", __func__ ); + for( unsigned i=0; iSetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL ); + prj->SetElem( PROJECT::ELEM_SCH_SEARCH_STACK, NULL ); + } +} + + +void SCH_EDIT_FRAME::Process_Config( wxCommandEvent& event ) +{ + int id = event.GetId(); + wxFileName fn; + + switch( id ) + { + case ID_CONFIG_SAVE: + SaveProjectSettings( true ); + break; + + case ID_CONFIG_READ: + { + fn = g_RootSheet->GetScreen()->GetFileName(); + fn.SetExt( ProjectFileExtension ); + + wxFileDialog dlg( this, _( "Read Project File" ), fn.GetPath(), + fn.GetFullName(), ProjectFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() == wxID_CANCEL ) + break; + + wxString chosen = dlg.GetPath(); + + if( chosen == Prj().GetProjectFullName() ) + LoadProjectFile(); + else + { + // Read library list and library path list + Prj().ConfigLoad( Kiface().KifaceSearch(), GROUP_SCH, GetProjectFileParametersList() ); + // Read schematic editor setup + Prj().ConfigLoad( Kiface().KifaceSearch(), GROUP_SCH_EDITOR, GetProjectFileParametersList() ); + } + } + break; + + // Hotkey IDs + case ID_PREFERENCES_HOTKEY_EXPORT_CONFIG: + ExportHotkeyConfigToFile( g_Eeschema_Hokeys_Descr, wxT( "eeschema" ) ); + break; + + case ID_PREFERENCES_HOTKEY_IMPORT_CONFIG: + ImportHotkeyConfigFromFile( g_Eeschema_Hokeys_Descr, wxT( "eeschema" ) ); + break; + + case ID_PREFERENCES_HOTKEY_SHOW_EDITOR: + InstallHotkeyFrame( this, g_Eeschema_Hokeys_Descr ); + break; + + case ID_PREFERENCES_HOTKEY_SHOW_CURRENT_LIST: + // Display current hotkey list for eeschema. + DisplayHotkeyList( this, g_Schematic_Hokeys_Descr ); + break; + + default: + DisplayError( this, wxT( "SCH_EDIT_FRAME::Process_Config error" ) ); + } +} + + +void SCH_EDIT_FRAME::OnPreferencesOptions( wxCommandEvent& event ) +{ + wxArrayString units; + GRIDS grid_list = GetScreen()->GetGrids(); + bool saveProjectConfig = false; + + DIALOG_EESCHEMA_OPTIONS dlg( this ); + + units.Add( GetUnitsLabel( INCHES ) ); + units.Add( GetUnitsLabel( MILLIMETRES ) ); + + dlg.SetUnits( units, g_UserUnit ); + dlg.SetGridSizes( grid_list, GetScreen()->GetGridCmdId() ); + dlg.SetBusWidth( GetDefaultBusThickness() ); + dlg.SetLineWidth( GetDefaultLineThickness() ); + dlg.SetTextSize( GetDefaultTextSize() ); + dlg.SetRepeatHorizontal( GetRepeatStep().x ); + dlg.SetRepeatVertical( GetRepeatStep().y ); + dlg.SetRepeatLabel( GetRepeatDeltaLabel() ); + dlg.SetAutoSaveInterval( GetAutoSaveInterval() / 60 ); + dlg.SetMaxUndoItems( GetScreen()->GetMaxUndoItems() ); + dlg.SetRefIdSeparator( LIB_PART::GetSubpartIdSeparator(), + LIB_PART::GetSubpartFirstId() ); + + dlg.SetShowGrid( IsGridVisible() ); + dlg.SetShowHiddenPins( m_showAllPins ); + dlg.SetEnableMiddleButtonPan( m_canvas->GetEnableMiddleButtonPan() ); + dlg.SetEnableMousewheelPan( m_canvas->GetEnableMousewheelPan() ); + dlg.SetEnableZoomNoCenter( m_canvas->GetEnableZoomNoCenter() ); + dlg.SetMiddleButtonPanLimited( m_canvas->GetMiddleButtonPanLimited() ); + dlg.SetEnableAutoPan( m_canvas->GetEnableAutoPan() ); + dlg.SetEnableHVBusOrientation( GetForceHVLines() ); + dlg.SetShowPageLimits( m_showPageLimits ); + dlg.Layout(); + dlg.Fit(); + dlg.SetMinSize( dlg.GetSize() ); + dlg.SetTemplateFields( m_TemplateFieldNames.GetTemplateFieldNames() ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + g_UserUnit = (EDA_UNITS_T)dlg.GetUnitsSelection(); + + wxRealPoint gridsize = grid_list[ (size_t) dlg.GetGridSelection() ].m_Size; + m_LastGridSizeId = GetScreen()->SetGrid( gridsize ); + + int sep, firstId; + dlg.GetRefIdSeparator( sep, firstId); + + if( sep != (int)LIB_PART::GetSubpartIdSeparator() || + firstId != (int)LIB_PART::GetSubpartFirstId() ) + { + LIB_PART::SetSubpartIdNotation( sep, firstId ); + saveProjectConfig = true; + } + + SetDefaultBusThickness( dlg.GetBusWidth() ); + SetDefaultLineThickness( dlg.GetLineWidth() ); + + if( dlg.GetTextSize() != GetDefaultTextSize() ) + { + SetDefaultTextSize( dlg.GetTextSize() ); + saveProjectConfig = true; + } + + wxPoint step; + step.x = dlg.GetRepeatHorizontal(); + step.y = dlg.GetRepeatVertical(); + SetRepeatStep( step ); + SetRepeatDeltaLabel( dlg.GetRepeatLabel() ); + + SetAutoSaveInterval( dlg.GetAutoSaveInterval() * 60 ); + GetScreen()->SetMaxUndoItems( dlg.GetMaxUndoItems() ); + SetGridVisibility( dlg.GetShowGrid() ); + m_showAllPins = dlg.GetShowHiddenPins(); + m_canvas->SetEnableMiddleButtonPan( dlg.GetEnableMiddleButtonPan() ); + m_canvas->SetEnableMousewheelPan( dlg.GetEnableMousewheelPan() ); + m_canvas->SetEnableZoomNoCenter( dlg.GetEnableZoomNoCenter() ); + m_canvas->SetMiddleButtonPanLimited( dlg.GetMiddleButtonPanLimited() ); + m_canvas->SetEnableAutoPan( dlg.GetEnableAutoPan() ); + SetForceHVLines( dlg.GetEnableHVBusOrientation() ); + m_showPageLimits = dlg.GetShowPageLimits(); + + // Delete all template fieldnames and then restore them using the template field data from + // the options dialog + DeleteAllTemplateFieldNames(); + TEMPLATE_FIELDNAMES newFieldNames = dlg.GetTemplateFields(); + + for( TEMPLATE_FIELDNAMES::iterator dlgfld = newFieldNames.begin(); + dlgfld != newFieldNames.end(); ++dlgfld ) + { + TEMPLATE_FIELDNAME fld = *dlgfld; + AddTemplateFieldName( fld ); + } + + SaveSettings( config() ); // save values shared by eeschema applications. + + if( saveProjectConfig ) + SaveProjectSettings( true ); + + m_canvas->Refresh( true ); +} + + +PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetProjectFileParametersList() +{ + if( !m_projectFileParams.empty() ) + return m_projectFileParams; + + m_projectFileParams.push_back( new PARAM_CFG_FILENAME( wxT( "PageLayoutDescrFile" ), + &BASE_SCREEN::m_PageLayoutDescrFileName ) ); + + m_projectFileParams.push_back( new PARAM_CFG_FILENAME( wxT( "PlotDirectoryName" ), + &m_plotDirectoryName ) ); + + m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "SubpartIdSeparator" ), + LIB_PART::SubpartIdSeparatorPtr(), + 0, 0, 126 ) ); + m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "SubpartFirstId" ), + LIB_PART::SubpartFirstIdPtr(), + 'A', '1', 'z' ) ); + + /* moved to library load/save specific code, in a specific section in .pro file + m_projectFileParams.push_back( new PARAM_CFG_FILENAME( wxT( "LibDir" ), + &m_userLibraryPath ) ); + m_projectFileParams.push_back( new PARAM_CFG_LIBNAME_LIST( wxT( "LibName" ), + &m_componentLibFiles, + GROUP_SCH_LIBS ) ); + */ + + m_projectFileParams.push_back( new PARAM_CFG_WXSTRING( wxT( "NetFmtName" ), + &m_netListFormat) ); + m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "SpiceForceRefPrefix" ), + &m_spiceNetlistAddReferencePrefix, false ) ); + m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "SpiceUseNetNumbers" ), + &m_spiceNetlistUseNetcodeAsNetname, false ) ); + + m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "LabSize" ), + &s_defaultTextSize, + DEFAULT_SIZE_TEXT, 5, + 1000 ) ); + + return m_projectFileParams; +} + + +bool SCH_EDIT_FRAME::LoadProjectFile() +{ + // Read library list and library path list + bool isRead = Prj().ConfigLoad( Kiface().KifaceSearch(), + GROUP_SCH, GetProjectFileParametersList() ); + + // Read schematic editor setup + isRead = isRead && Prj().ConfigLoad( Kiface().KifaceSearch(), + GROUP_SCH_EDITOR, GetProjectFileParametersList() ); + + // Verify some values, because the config file can be edited by hand, + // and have bad values: + LIB_PART::SetSubpartIdNotation( + LIB_PART::GetSubpartIdSeparator(), + LIB_PART::GetSubpartFirstId() ); + + // Load the page layout decr file, from the filename stored in + // BASE_SCREEN::m_PageLayoutDescrFileName, read in config project file + // If empty, or not existing, the default descr is loaded + WORKSHEET_LAYOUT& pglayout = WORKSHEET_LAYOUT::GetTheInstance(); + wxString pg_fullfilename = WORKSHEET_LAYOUT::MakeFullFileName( + BASE_SCREEN::m_PageLayoutDescrFileName, + Prj().GetProjectPath() ); + + pglayout.SetPageLayout( pg_fullfilename ); + + return isRead; +} + + +void SCH_EDIT_FRAME::SaveProjectSettings( bool aAskForSave ) +{ + PROJECT& prj = Prj(); + wxFileName fn = g_RootSheet->GetScreen()->GetFileName(); //ConfigFileName + + fn.SetExt( ProjectFileExtension ); + + if( !IsWritable( fn ) ) + return; + + if( aAskForSave ) + { + wxFileDialog dlg( this, _( "Save Project File" ), + fn.GetPath(), fn.GetFullName(), + ProjectFileWildcard, wxFD_SAVE ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + fn = dlg.GetPath(); + } + + prj.ConfigSave( Kiface().KifaceSearch(), GROUP_SCH_EDITOR, GetProjectFileParametersList() ); +} + + +static const wxChar DefaultBusWidthEntry[] = wxT( "DefaultBusWidth" ); +static const wxChar DefaultDrawLineWidthEntry[] = wxT( "DefaultDrawLineWidth" ); +static const wxChar ShowHiddenPinsEntry[] = wxT( "ShowHiddenPins" ); +static const wxChar HorzVertLinesOnlyEntry[] = wxT( "HorizVertLinesOnly" ); +static const wxChar PreviewFramePositionXEntry[] = wxT( "PreviewFramePositionX" ); +static const wxChar PreviewFramePositionYEntry[] = wxT( "PreviewFramePositionY" ); +static const wxChar PreviewFrameWidthEntry[] = wxT( "PreviewFrameWidth" ); +static const wxChar PreviewFrameHeightEntry[] = wxT( "PreviewFrameHeight" ); +static const wxChar PrintDialogPositionXEntry[] = wxT( "PrintDialogPositionX" ); +static const wxChar PrintDialogPositionYEntry[] = wxT( "PrintDialogPositionY" ); +static const wxChar PrintDialogWidthEntry[] = wxT( "PrintDialogWidth" ); +static const wxChar PrintDialogHeightEntry[] = wxT( "PrintDialogHeight" ); +static const wxChar FindDialogPositionXEntry[] = wxT( "FindDialogPositionX" ); +static const wxChar FindDialogPositionYEntry[] = wxT( "FindDialogPositionY" ); +static const wxChar FindDialogWidthEntry[] = wxT( "FindDialogWidth" ); +static const wxChar FindDialogHeightEntry[] = wxT( "FindDialogHeight" ); +static const wxChar FindReplaceFlagsEntry[] = wxT( "LastFindReplaceFlags" ); +static const wxChar FindStringEntry[] = wxT( "LastFindString" ); +static const wxChar ReplaceStringEntry[] = wxT( "LastReplaceString" ); +static const wxChar FindStringHistoryEntry[] = wxT( "FindStringHistoryList%d" ); +static const wxChar ReplaceStringHistoryEntry[] = wxT( "ReplaceStringHistoryList%d" ); +static const wxChar FieldNamesEntry[] = wxT( "FieldNames" ); +static const wxChar SimulatorCommandEntry[] = wxT( "SimCmdLine" ); + +// Library editor wxConfig entry names. +static const wxChar lastLibExportPathEntry[] = wxT( "LastLibraryExportPath" ); +static const wxChar lastLibImportPathEntry[] = wxT( "LastLibraryImportPath" ); +static const wxChar defaultPinNumSizeEntry[] = wxT( "LibeditPinNumSize" ); +static const wxChar defaultPinNameSizeEntry[] = wxT( "LibeditPinNameSize" ); +static const wxChar DefaultPinLengthEntry[] = wxT( "DefaultPinLength" ); +static const wxChar repeatLibLabelIncEntry[] = wxT( "LibeditRepeatLabelInc" ); +static const wxChar pinRepeatStepEntry[] = wxT( "LibeditPinRepeatStep" ); +static const wxChar repeatLibStepXEntry[] = wxT( "LibeditRepeatStepX" ); +static const wxChar repeatLibStepYEntry[] = wxT( "LibeditRepeatStepY" ); + + +PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetConfigurationSettings() +{ + if( !m_configSettings.empty() ) + return m_configSettings; + + m_configSettings.push_back( new PARAM_CFG_BOOL( true, wxT( "ShowPageLimits" ), + &m_showPageLimits, true ) ); + m_configSettings.push_back( new PARAM_CFG_INT( true, wxT( "Units" ), + (int*)&g_UserUnit, MILLIMETRES ) ); + + m_configSettings.push_back( new PARAM_CFG_BOOL( true, wxT( "PrintMonochrome" ), + &m_printMonochrome, true ) ); + m_configSettings.push_back( new PARAM_CFG_BOOL( true, wxT( "PrintSheetReferenceAndTitleBlock" ), + &m_printSheetReference, true ) ); + + m_configSettings.push_back( new PARAM_CFG_INT( true, wxT( "RepeatStepX" ), + &m_repeatStep.x, + DEFAULT_REPEAT_OFFSET_X, + -REPEAT_OFFSET_MAX, + REPEAT_OFFSET_MAX ) ); + m_configSettings.push_back( new PARAM_CFG_INT( true, wxT( "RepeatStepY" ), + &m_repeatStep.y, + DEFAULT_REPEAT_OFFSET_Y, + -REPEAT_OFFSET_MAX, + REPEAT_OFFSET_MAX ) ); + m_configSettings.push_back( new PARAM_CFG_INT( true, wxT( "RepeatLabelIncrement" ), + &m_repeatDeltaLabel, + DEFAULT_REPEAT_LABEL_INC, -10, +10 ) ); + return m_configSettings; +} + + +void SCH_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::LoadSettings( aCfg ); + + long tmp; + + wxConfigLoadSetups( aCfg, GetConfigurationSettings() ); + + SetGridColor( GetLayerColor( LAYER_GRID ) ); + SetDrawBgColor( GetLayerColor( LAYER_BACKGROUND ) ); + + SetDefaultBusThickness( aCfg->Read( DefaultBusWidthEntry, DEFAULTBUSTHICKNESS ) ); + SetDefaultLineThickness( aCfg->Read( DefaultDrawLineWidthEntry, DEFAULTDRAWLINETHICKNESS ) ); + aCfg->Read( ShowHiddenPinsEntry, &m_showAllPins, false ); + aCfg->Read( HorzVertLinesOnlyEntry, &m_forceHVLines, true ); + + // Load print preview window session settings. + aCfg->Read( PreviewFramePositionXEntry, &tmp, -1 ); + m_previewPosition.x = (int) tmp; + aCfg->Read( PreviewFramePositionYEntry, &tmp, -1 ); + m_previewPosition.y = (int) tmp; + aCfg->Read( PreviewFrameWidthEntry, &tmp, -1 ); + m_previewSize.SetWidth( (int) tmp ); + aCfg->Read( PreviewFrameHeightEntry, &tmp, -1 ); + m_previewSize.SetHeight( (int) tmp ); + + // Load print dialog session settings. + aCfg->Read( PrintDialogPositionXEntry, &tmp, -1 ); + m_printDialogPosition.x = (int) tmp; + aCfg->Read( PrintDialogPositionYEntry, &tmp, -1 ); + m_printDialogPosition.y = (int) tmp; + aCfg->Read( PrintDialogWidthEntry, &tmp, -1 ); + m_printDialogSize.SetWidth( (int) tmp ); + aCfg->Read( PrintDialogHeightEntry, &tmp, -1 ); + m_printDialogSize.SetHeight( (int) tmp ); + + // Load netlists options: + aCfg->Read( SimulatorCommandEntry, &m_simulatorCommand ); + + // Load find dialog session setting. + aCfg->Read( FindDialogPositionXEntry, &tmp, -1 ); + m_findDialogPosition.x = (int) tmp; + aCfg->Read( FindDialogPositionYEntry, &tmp, -1 ); + m_findDialogPosition.y = (int) tmp; + aCfg->Read( FindDialogWidthEntry, &tmp, -1 ); + m_findDialogSize.SetWidth( (int) tmp ); + aCfg->Read( FindDialogHeightEntry, &tmp, -1 ); + m_findDialogSize.SetHeight( (int) tmp ); + + wxASSERT_MSG( m_findReplaceData, + wxT( "Find dialog data settings object not created. Bad programmer!" ) ); + + aCfg->Read( FindReplaceFlagsEntry, &tmp, (long) wxFR_DOWN ); + m_findReplaceData->SetFlags( (wxUint32) tmp & ~FR_REPLACE_ITEM_FOUND ); + m_findReplaceData->SetFindString( aCfg->Read( FindStringEntry, wxEmptyString ) ); + m_findReplaceData->SetReplaceString( aCfg->Read( ReplaceStringEntry, wxEmptyString ) ); + + // Load the find and replace string history list. + for( int i = 0; i < FR_HISTORY_LIST_CNT; ++i ) + { + wxString tmpHistory; + wxString entry; + entry.Printf( FindStringHistoryEntry, i ); + tmpHistory = aCfg->Read( entry, wxEmptyString ); + + if( !tmpHistory.IsEmpty() ) + m_findStringHistoryList.Add( tmpHistory ); + + entry.Printf( ReplaceStringHistoryEntry, i ); + tmpHistory = aCfg->Read( entry, wxEmptyString ); + + if( !tmpHistory.IsEmpty() ) + m_replaceStringHistoryList.Add( tmpHistory ); + } + + wxString templateFieldNames = aCfg->Read( FieldNamesEntry, wxEmptyString ); + + if( !templateFieldNames.IsEmpty() ) + { + TEMPLATE_FIELDNAMES_LEXER lexer( TO_UTF8( templateFieldNames ) ); + + try + { + m_TemplateFieldNames.Parse( &lexer ); + } + catch( const IO_ERROR& e ) + { + // @todo show error msg + DBG( printf( "templatefieldnames parsing error: '%s'\n", + TO_UTF8( e.errorText ) ); ) + } + } +} + + +void SCH_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::SaveSettings( aCfg ); + + wxConfigSaveSetups( aCfg, GetConfigurationSettings() ); + + aCfg->Write( DefaultBusWidthEntry, (long) GetDefaultBusThickness() ); + aCfg->Write( DefaultDrawLineWidthEntry, (long) GetDefaultLineThickness() ); + aCfg->Write( ShowHiddenPinsEntry, m_showAllPins ); + aCfg->Write( HorzVertLinesOnlyEntry, GetForceHVLines() ); + + // Save print preview window session settings. + aCfg->Write( PreviewFramePositionXEntry, m_previewPosition.x ); + aCfg->Write( PreviewFramePositionYEntry, m_previewPosition.y ); + aCfg->Write( PreviewFrameWidthEntry, m_previewSize.GetWidth() ); + aCfg->Write( PreviewFrameHeightEntry, m_previewSize.GetHeight() ); + + // Save print dialog session settings. + aCfg->Write( PrintDialogPositionXEntry, m_printDialogPosition.x ); + aCfg->Write( PrintDialogPositionYEntry, m_printDialogPosition.y ); + aCfg->Write( PrintDialogWidthEntry, m_printDialogSize.GetWidth() ); + aCfg->Write( PrintDialogHeightEntry, m_printDialogSize.GetHeight() ); + + // Save netlists options: + aCfg->Write( SimulatorCommandEntry, m_simulatorCommand ); + + // Save find dialog session setting. + aCfg->Write( FindDialogPositionXEntry, m_findDialogPosition.x ); + aCfg->Write( FindDialogPositionYEntry, m_findDialogPosition.y ); + aCfg->Write( FindDialogWidthEntry, m_findDialogSize.GetWidth() ); + aCfg->Write( FindDialogHeightEntry, m_findDialogSize.GetHeight() ); + wxASSERT_MSG( m_findReplaceData, + wxT( "Find dialog data settings object not created. Bad programmer!" ) ); + aCfg->Write( FindReplaceFlagsEntry, + (long) m_findReplaceData->GetFlags() & ~FR_REPLACE_ITEM_FOUND ); + aCfg->Write( FindStringEntry, m_findReplaceData->GetFindString() ); + aCfg->Write( ReplaceStringEntry, m_findReplaceData->GetReplaceString() ); + + // Save the find and replace string history list. + unsigned i; + wxString tmpHistory; + wxString entry; // invoke constructor outside of any loops + + for( i = 0; i < m_findStringHistoryList.GetCount() && i < FR_HISTORY_LIST_CNT; i++ ) + { + entry.Printf( FindStringHistoryEntry, i ); + aCfg->Write( entry, m_findStringHistoryList[ i ] ); + } + + for( i = 0; i < m_replaceStringHistoryList.GetCount() && i < FR_HISTORY_LIST_CNT; i++ ) + { + entry.Printf( ReplaceStringHistoryEntry, i ); + aCfg->Write( entry, m_replaceStringHistoryList[ i ] ); + } + + // Save template fieldnames + STRING_FORMATTER sf; + m_TemplateFieldNames.Format( &sf, 0 ); + + wxString record = FROM_UTF8( sf.GetString().c_str() ); + record.Replace( wxT("\n"), wxT(""), true ); // strip all newlines + record.Replace( wxT(" "), wxT(" "), true ); // double space to single + + aCfg->Write( FieldNamesEntry, record ); +} + + +void LIB_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::LoadSettings( aCfg ); + + SetGridColor( GetLayerColor( LAYER_GRID ) ); + SetDrawBgColor( GetLayerColor( LAYER_BACKGROUND ) ); + + SetDefaultLineThickness( aCfg->Read( DefaultDrawLineWidthEntry, DEFAULTDRAWLINETHICKNESS ) ); + SetDefaultPinLength( aCfg->Read( DefaultPinLengthEntry, DEFAULTPINLENGTH ) ); + m_textPinNumDefaultSize = aCfg->Read( defaultPinNumSizeEntry, DEFAULTPINNUMSIZE ); + m_textPinNameDefaultSize = aCfg->Read( defaultPinNameSizeEntry, DEFAULTPINNAMESIZE ); + SetRepeatDeltaLabel( aCfg->Read( repeatLibLabelIncEntry, DEFAULT_REPEAT_LABEL_INC ) ); + SetRepeatPinStep( aCfg->Read( pinRepeatStepEntry, DEFAULT_REPEAT_OFFSET_PIN ) ); + wxPoint step; + step.x = aCfg->Read( repeatLibStepXEntry, (long)DEFAULT_REPEAT_OFFSET_X ); + step.y = aCfg->Read( repeatLibStepYEntry, (long)DEFAULT_REPEAT_OFFSET_Y ); + SetRepeatStep( step ); +} + + +void LIB_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::SaveSettings( aCfg ); + + aCfg->Write( DefaultPinLengthEntry, (long) GetDefaultPinLength() ); + aCfg->Write( defaultPinNumSizeEntry, (long) GetPinNumDefaultSize() ); + aCfg->Write( defaultPinNameSizeEntry, (long) GetPinNameDefaultSize() ); + aCfg->Write( repeatLibLabelIncEntry, (long) GetRepeatDeltaLabel() ); + aCfg->Write( pinRepeatStepEntry, (long) GetRepeatPinStep() ); + aCfg->Write( repeatLibStepXEntry, (long) GetRepeatStep().x ); + aCfg->Write( repeatLibStepYEntry, (long) GetRepeatStep().y ); +} + + +void LIB_EDIT_FRAME::OnPreferencesOptions( wxCommandEvent& event ) +{ + wxArrayString units; + GRIDS grid_list = GetScreen()->GetGrids(); + + DIALOG_LIBEDIT_OPTIONS dlg( this ); + + dlg.SetGridSizes( grid_list, GetScreen()->GetGridCmdId() ); + dlg.SetLineWidth( GetDefaultLineThickness() ); + dlg.SetPinLength( GetDefaultPinLength() ); + dlg.SetPinNumSize( m_textPinNumDefaultSize ); + dlg.SetPinNameSize( m_textPinNameDefaultSize ); + dlg.SetMaxUndoItems( GetScreen()->GetMaxUndoItems() ); + + dlg.SetShowGrid( IsGridVisible() ); + dlg.Layout(); + dlg.Fit(); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + wxRealPoint gridsize = grid_list[ (size_t) dlg.GetGridSelection() ].m_Size; + m_LastGridSizeId = GetScreen()->SetGrid( gridsize ); + + SetDefaultLineThickness( dlg.GetLineWidth() ); + SetDefaultPinLength( dlg.GetPinLength() ); + m_textPinNumDefaultSize = dlg.GetPinNumSize(); + m_textPinNameDefaultSize = dlg.GetPinNameSize(); + SetGridVisibility( dlg.GetShowGrid() ); + SetRepeatPinStep( dlg.GetPinRepeatStep() ); + SetRepeatStep( dlg.GetItemRepeatStep() ); + SetRepeatDeltaLabel( dlg.GetRepeatLabelInc() ); + GetScreen()->SetMaxUndoItems( dlg.GetMaxUndoItems() ); + + SaveSettings( config() ); // save values shared by eeschema applications. + + m_canvas->Refresh( true ); +} + diff --git a/eeschema/eeschema_config.h b/eeschema/eeschema_config.h new file mode 100644 index 00000000..e93160b5 --- /dev/null +++ b/eeschema/eeschema_config.h @@ -0,0 +1,13 @@ +/** + * @file eeschema_config.h + */ + +#ifndef EESCHEMA_CONFIG_H +#define EESCHEMA_CONFIG_H + +#include + +// a key to read write in user config the visibility of the rescue library dialog +#define RESCUE_NEVER_SHOW_KEY wxT("RescueNeverShow") + +#endif // EESCHEMA_CONFIG_H diff --git a/eeschema/eeschema_doc.icns b/eeschema/eeschema_doc.icns new file mode 100644 index 00000000..7d2e0ebc Binary files /dev/null and b/eeschema/eeschema_doc.icns differ diff --git a/eeschema/eeschema_id.h b/eeschema/eeschema_id.h new file mode 100644 index 00000000..ca8eeeb8 --- /dev/null +++ b/eeschema/eeschema_id.h @@ -0,0 +1,252 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2008 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema_id.h + */ + +#ifndef __EESCHEMA_ID_H__ +#define __EESCHEMA_ID_H__ + + +#include + + +/** + * The maximum number of items in the clarify selection context menu. It is + * highly unlikely that there would ever be more than 10 items at the current + * cursor. Increase this number if that ever becomes a problem. + */ +#define MAX_SELECT_ITEM_IDS 10 + +/** + * The maximum number of units per package. + * Increase this number if that ever becomes a problem, but remember + * the popup menu to select a given unit could be not easy to use. + */ +#define MAX_UNIT_COUNT_PER_PACKAGE 64 + + +/** + * Command IDs for the schematic editor. + * + * Please add IDs that are unique to the schematic editor (Eeschema) here and + * not in the global id.h file. This will prevent the entire project from + * being rebuilt when adding new command to Eeschema. + */ + +enum id_eeschema_frm +{ + ID_UPDATE_ONE_SHEET = ID_END_LIST, + ID_SAVE_ONE_SHEET_UNDER_NEW_NAME, + + /* Schematic editor main menubar IDs. */ + ID_RESCUE_CACHED, + + /* Schematic editor horizontal toolbar IDs */ + ID_HIERARCHY, + ID_TO_LIBVIEW, + ID_GET_ANNOTATE, + ID_GET_ERC, + ID_BACKANNO_ITEMS, + ID_GEN_PLOT_SCHEMATIC, + + /* Schematic editor veritcal toolbar IDs */ + ID_SCHEMATIC_VERTICAL_TOOLBAR_START, + ID_HIERARCHY_PUSH_POP_BUTT, + ID_SCH_PLACE_COMPONENT, + ID_PLACE_POWER_BUTT, + ID_BUS_BUTT, + ID_WIRE_BUTT, + ID_BUSTOBUS_ENTRY_BUTT, + ID_WIRETOBUS_ENTRY_BUTT, + ID_LABEL_BUTT, + ID_GLABEL_BUTT, + ID_HIERLABEL_BUTT, + ID_IMPORT_HLABEL_BUTT, + ID_SHEET_PIN_BUTT, + ID_NOCONN_BUTT, + ID_JUNCTION_BUTT, + ID_SHEET_SYMBOL_BUTT, + ID_TEXT_COMMENT_BUTT, + ID_LINE_COMMENT_BUTT, + ID_ADD_IMAGE_BUTT, + ID_SCHEMATIC_DELETE_ITEM_BUTT, + ID_SCHEMATIC_VERTICAL_TOOLBAR_END, + + // Toolbar options id: + ID_TB_OPTIONS_HIDDEN_PINS, + ID_TB_OPTIONS_BUS_WIRES_ORIENT, + + /* Schematic editor context menu IDs. */ + ID_POPUP_SCH_COPY_ITEM, + + ID_POPUP_START_RANGE, + ID_POPUP_SCH_DELETE, + ID_POPUP_SCH_BREAK_WIRE, + ID_POPUP_SCH_BEGIN_WIRE, + ID_POPUP_SCH_BEGIN_BUS, + ID_POPUP_END_LINE, + ID_POPUP_SCH_DELETE_CONNECTION, + ID_POPUP_SCH_DELETE_NODE, + ID_POPUP_SCH_DELETE_CMP, + ID_POPUP_SCH_ENTRY_SELECT_SLASH, + ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH, + + ID_POPUP_SCH_INIT_CMP, + + ID_POPUP_SCH_SET_SHAPE_TEXT, + ID_POPUP_SCH_END_SHEET, + ID_POPUP_SCH_RESIZE_SHEET, + ID_POPUP_SCH_CLEANUP_SHEET, + ID_POPUP_IMPORT_HLABEL_TO_SHEETPIN, + ID_POPUP_SCH_GENERIC_ORIENT_CMP, + ID_POPUP_SCH_GENERIC_EDIT_CMP, + ID_POPUP_SCH_EDIT_CONVERT_CMP, + ID_POPUP_SCH_EDIT_FIELD, + ID_POPUP_SCH_DISPLAYDOC_CMP, + ID_POPUP_SCH_ENTER_SHEET, + ID_POPUP_SCH_LEAVE_SHEET, + ID_POPUP_SCH_ADD_JUNCTION, + ID_POPUP_SCH_ADD_LABEL, + ID_POPUP_SCH_ADD_GLABEL, + ID_POPUP_SCH_GETINFO_MARKER, + ID_POPUP_END_RANGE, + + ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP, + + // Unit select context menus command IDs. + ID_POPUP_SCH_SELECT_UNIT_CMP, + ID_POPUP_SCH_SELECT_UNIT1, + // ... leave room for MAX_UNIT_COUNT_PER_PACKAGE IDs , + // to select one unit among MAX_UNIT_COUNT_PER_PACKAGE in popup menu + ID_POPUP_SCH_SELECT_UNIT_CMP_MAX = ID_POPUP_SCH_SELECT_UNIT1 + + MAX_UNIT_COUNT_PER_PACKAGE, + + // Change text type context menu command IDs. + ID_POPUP_SCH_CHANGE_TYPE_TEXT, + ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_LABEL, + ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_GLABEL, + ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_HLABEL, + ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT, + + ID_SELECT_ITEM_START, + ID_SELECT_ITEM_END = ID_SELECT_ITEM_START + MAX_SELECT_ITEM_IDS, + + // Change orientation command IDs. + ID_SCH_MIRROR_X, + ID_SCH_MIRROR_Y, + ID_SCH_ORIENT_NORMAL, + + ID_SCH_ROTATE_CLOCKWISE, + ID_SCH_ROTATE_COUNTERCLOCKWISE, + ID_SCH_EDIT_ITEM, + ID_SCH_EDIT_COMPONENT_VALUE, + ID_SCH_EDIT_COMPONENT_REFERENCE, + ID_SCH_EDIT_COMPONENT_FOOTPRINT, + ID_SCH_MOVE_ITEM, + ID_SCH_DRAG_ITEM, + + // Schematic editor commmands. These are command IDs that are generated by multiple + // events (menus, toolbar, context menu, etc.) that result in the same event handler. + ID_CANCEL_CURRENT_COMMAND, + + /* Library editor main menubar IDs. */ + ID_LIBEDIT_DIMENSIONS, + + /* Library editor horizontal toolbar IDs. */ + ID_LIBEDIT_SELECT_PART, + ID_LIBEDIT_SELECT_CURRENT_LIB, + ID_LIBEDIT_SAVE_CURRENT_LIB, + ID_LIBEDIT_SAVE_CURRENT_PART, + ID_LIBEDIT_NEW_PART, + ID_LIBEDIT_NEW_PART_FROM_EXISTING, + ID_LIBEDIT_GET_FRAME_EDIT_PART, + ID_LIBEDIT_GET_FRAME_EDIT_FIELDS, + ID_LIBEDIT_DELETE_PART, + ID_DE_MORGAN_NORMAL_BUTT, + ID_DE_MORGAN_CONVERT_BUTT, + ID_LIBEDIT_EDIT_PIN_BY_PIN, + ID_LIBEDIT_EDIT_PIN_BY_TABLE, + ID_LIBEDIT_VIEW_DOC, + ID_LIBEDIT_CHECK_PART, + + ID_LIBEDIT_SELECT_PART_NUMBER, + ID_LIBEDIT_SELECT_ALIAS, + + /* Library editor vertical toolbar IDs. */ + ID_LIBEDIT_PIN_BUTT, + ID_LIBEDIT_BODY_LINE_BUTT, + ID_LIBEDIT_BODY_ARC_BUTT, + ID_LIBEDIT_BODY_CIRCLE_BUTT, + ID_LIBEDIT_BODY_RECT_BUTT, + ID_LIBEDIT_BODY_TEXT_BUTT, + ID_LIBEDIT_ANCHOR_ITEM_BUTT, + ID_LIBEDIT_IMPORT_BODY_BUTT, + ID_LIBEDIT_EXPORT_BODY_BUTT, + ID_LIBEDIT_DELETE_ITEM_BUTT, + + ID_LIBEDIT_ROTATE_ITEM, + + /* Library editor context menu IDs */ + ID_LIBEDIT_EDIT_PIN, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_ITEM, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM, + ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, + ID_POPUP_LIBEDIT_DELETE_ITEM, + ID_POPUP_LIBEDIT_MODIFY_ITEM, + ID_POPUP_LIBEDIT_END_CREATE_ITEM, + ID_POPUP_LIBEDIT_CANCEL_EDITING, + ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, + ID_POPUP_LIBEDIT_FIELD_EDIT_ITEM, + ID_POPUP_LIBEDIT_DELETE_CURRENT_POLY_SEGMENT, + + /* Library editor menubar IDs */ + ID_LIBEDIT_SAVE_CURRENT_LIB_AS, + ID_LIBEDIT_GEN_PNG_FILE, + ID_LIBEDIT_GEN_SVG_FILE, + + /* Library viewer horizontal toolbar IDs */ + ID_LIBVIEW_NEXT, + ID_LIBVIEW_PREVIOUS, + ID_LIBVIEW_SELECT_PART, + ID_LIBVIEW_SELECT_LIB, + ID_LIBVIEW_VIEWDOC, + ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, + ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, + ID_LIBVIEW_SELECT_PART_NUMBER, + ID_LIBVIEW_LIB_LIST, + ID_LIBVIEW_CMP_LIST, + ID_LIBVIEW_LIBWINDOW, + ID_LIBVIEW_CMPWINDOW, + ID_LIBVIEW_CMP_EXPORT_TO_SCHEMATIC, + ID_SET_RELATIVE_OFFSET, + + ID_END_EESCHEMA_ID_LIST +}; + + +#endif /* __EESCHEMA_ID_H__ */ diff --git a/eeschema/erc.cpp b/eeschema/erc.cpp new file mode 100644 index 00000000..099249cf --- /dev/null +++ b/eeschema/erc.cpp @@ -0,0 +1,617 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file erc.cpp + * @brief Electrical Rules Check implementation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* ERC tests : + * 1 - conflicts between connected pins ( example: 2 connected outputs ) + * 2 - minimal connections requirements ( 1 input *must* be connected to an + * output, or a passive pin ) + */ + + +/* + * Electrical type of pins: + * PIN_INPUT = usual pin input: must be connected + * PIN_OUTPUT = usual output + * PIN_BIDI = input or output (like port for a microprocessor) + * PIN_TRISTATE = tris state bus pin + * PIN_PASSIVE = pin for passive components: must be connected, and can be + * connected to any pin + * PIN_UNSPECIFIED = unknown electrical properties: creates always a warning + * when connected + * PIN_POWER_IN = power input (GND, VCC for ICs). Must be connected to a power + * output. + * PIN_POWER_OUT = output of a regulator: intended to be connected to power + * input pins + * PIN_OPENCOLLECTOR = pin type open collector + * PIN_OPENEMITTER = pin type open emitter + * PIN_NC = not connected (must be left open) + * + * Minimal requirements: + * All pins *must* be connected (except PIN_NC). + * When a pin is not connected in schematic, the user must place a "non + * connected" symbol to this pin. + * This ensures a forgotten connection will be detected. + */ + +/* Messages for conflicts : + * PIN_INPUT, PIN_OUTPUT, PIN_BIDI, PIN_TRISTATE, PIN_PASSIVE, + * PIN_UNSPECIFIED, PIN_POWER_IN, PIN_POWER_OUT, PIN_OPENCOLLECTOR, + * PIN_OPENEMITTER, PIN_NC + * These messages are used to show the ERC matrix in ERC dialog + */ + +// Messages for matrix rows: +const wxString CommentERC_H[] = +{ + _( "Input Pin.........." ), + _( "Output Pin........." ), + _( "Bidirectional Pin.." ), + _( "Tri-State Pin......" ), + _( "Passive Pin........" ), + _( "Unspecified Pin...." ), + _( "Power Input Pin...." ), + _( "Power Output Pin..." ), + _( "Open Collector....." ), + _( "Open Emitter......." ), + _( "No Connection......" ) +}; + +// Messages for matrix columns +const wxString CommentERC_V[] = +{ + _( "Input Pin" ), + _( "Output Pin" ), + _( "Bidirectional Pin" ), + _( "Tri-State Pin" ), + _( "Passive Pin" ), + _( "Unspecified Pin" ), + _( "Power Input Pin" ), + _( "Power Output Pin" ), + _( "Open Collector" ), + _( "Open Emitter" ), + _( "No Connection" ) +}; + + +/* Look up table which gives the diag for a pair of connected pins + * Can be modified by ERC options. + * at start up: must be loaded by DefaultDiagErc + */ +int DiagErc[PIN_NMAX][PIN_NMAX]; +bool DiagErcTableInit; // go to true after DiagErc init + +/** + * Default Look up table which gives the ERC error level for a pair of connected pins + * Same as DiagErc, but cannot be modified. + * Used to init or reset DiagErc + * note also, to avoid inconsistancy: + * DefaultDiagErc[i][j] = DefaultDiagErc[j][i] + */ +int DefaultDiagErc[PIN_NMAX][PIN_NMAX] = +{ +/* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */ +/* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, +/* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR }, +/* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR }, +/* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR }, +/*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, +/*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR }, +/*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR }, +/*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR }, +/* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, +/* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, +/* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR } +}; + + +/** + * Look up table which gives the minimal drive for a pair of connected pins on + * a net. + *

      + * The initial state of a net is NOC (Net with No Connection). It can be updated to + * NPI (Pin Isolated), NET_NC (Net with a no connect symbol), NOD (Not Driven) or DRV + * (DRIven). It can be updated to NET_NC with no error only if there is only one pin + * in net. Nets are OK when their final state is NET_NC or DRV. Nets with the state + * NOD have no valid source signal. + */ +static int MinimalReq[PIN_NMAX][PIN_NMAX] = +{ +/* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */ +/* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, +/* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI }, +/*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, +/* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI } +}; + + +int TestDuplicateSheetNames( bool aCreateMarker ) +{ + SCH_SCREEN* screen; + SCH_ITEM* item; + SCH_ITEM* test_item; + int err_count = 0; + SCH_SCREENS screenList; // Created the list of screen + + for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() ) + { + for( item = screen->GetDrawItems(); item != NULL; item = item->Next() ) + { + // search for a sheet; + if( item->Type() != SCH_SHEET_T ) + continue; + + for( test_item = item->Next(); test_item != NULL; test_item = test_item->Next() ) + { + if( test_item->Type() != SCH_SHEET_T ) + continue; + + // We have found a second sheet: compare names + if( ( (SCH_SHEET*) item )->GetName().CmpNoCase( + ( ( SCH_SHEET* ) test_item )->GetName() ) == 0 ) + { + if( aCreateMarker ) + { + /* Create a new marker type ERC error*/ + SCH_MARKER* marker = new SCH_MARKER(); + marker->SetTimeStamp( GetNewTimeStamp() ); + marker->SetData( ERCE_DUPLICATE_SHEET_NAME, + ( (SCH_SHEET*) test_item )->GetPosition(), + _( "Duplicate sheet name" ), + ( (SCH_SHEET*) test_item )->GetPosition() ); + marker->SetMarkerType( MARKER_BASE::MARKER_ERC ); + marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR ); + screen->Append( marker ); + } + + err_count++; + } + } + } + } + + return err_count; +} + + +void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, + int aMinConn, int aDiag ) +{ + SCH_MARKER* marker = NULL; + SCH_SCREEN* screen; + int ii, jj; + + if( aDiag == OK ) + return; + + /* Create new marker for ERC error. */ + marker = new SCH_MARKER(); + marker->SetTimeStamp( GetNewTimeStamp() ); + + marker->SetMarkerType( MARKER_BASE::MARKER_ERC ); + marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING ); + screen = aNetItemRef->m_SheetPath.LastScreen(); + screen->Append( marker ); + + wxString msg; + + if( aMinConn < 0 ) + { + if( (aNetItemRef->m_Type == NET_HIERLABEL) + || (aNetItemRef->m_Type == NET_HIERBUSLABELMEMBER) ) + { + msg.Printf( _( "Hierarchical label %s is not connected to a sheet label." ), + GetChars( aNetItemRef->m_Label ) ); + marker->SetData( ERCE_HIERACHICAL_LABEL, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + } + else if( (aNetItemRef->m_Type == NET_GLOBLABEL) ) + { + msg.Printf( _( "Global label %s is not connected to any other global label." ), + GetChars( aNetItemRef->m_Label ) ); + marker->SetData( ERCE_GLOBLABEL, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + } + else + { + msg.Printf( _( "Sheet label %s is not connected to a hierarchical label." ), + GetChars( aNetItemRef->m_Label ) ); + marker->SetData( ERCE_HIERACHICAL_LABEL, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + } + + return; + } + + ii = aNetItemRef->m_ElectricalType; + + wxString string_pinnum, cmp_ref; + char ascii_buf[5]; + ascii_buf[4] = 0; + memcpy( ascii_buf, &aNetItemRef->m_PinNum, 4 ); + string_pinnum = FROM_UTF8( ascii_buf ); + cmp_ref = wxT( "?" ); + + if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link ) + cmp_ref = aNetItemRef->GetComponentParent()->GetRef( &aNetItemRef->m_SheetPath ); + + if( aNetItemTst == NULL ) + { + if( aMinConn == NOC ) /* Only 1 element in the net. */ + { + msg.Printf( _( "Pin %s (%s) of component %s is unconnected." ), + GetChars( string_pinnum ), + GetChars( LIB_PIN::GetElectricalTypeName( ii ) ), + GetChars( cmp_ref ) ); + marker->SetData( ERCE_PIN_NOT_CONNECTED, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + return; + } + + if( aMinConn == NOD ) /* Nothing driving the net. */ + { + if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link ) + cmp_ref = aNetItemRef->GetComponentParent()->GetRef( + &aNetItemRef->m_SheetPath ); + + msg.Printf( _( "Pin %s (%s) of component %s is not driven (Net %d)." ), + GetChars( string_pinnum ), + GetChars( LIB_PIN::GetElectricalTypeName( ii ) ), + GetChars( cmp_ref ), + aNetItemRef->GetNet() ); + marker->SetData( ERCE_PIN_NOT_DRIVEN, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + return; + } + + if( aDiag == UNC ) + { + msg.Printf( _( "More than 1 pin connected to an UnConnect symbol." ) ); + marker->SetData( ERCE_NOCONNECT_CONNECTED, + aNetItemRef->m_Start, + msg, + aNetItemRef->m_Start ); + return; + } + } + + if( aNetItemTst ) /* Error between 2 pins */ + { + jj = aNetItemTst->m_ElectricalType; + int errortype = ERCE_PIN_TO_PIN_WARNING; + + if( aDiag == ERR ) + { + marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR ); + errortype = ERCE_PIN_TO_PIN_ERROR; + } + + wxString alt_string_pinnum, alt_cmp; + memcpy( ascii_buf, &aNetItemTst->m_PinNum, 4 ); + alt_string_pinnum = FROM_UTF8( ascii_buf ); + alt_cmp = wxT( "?" ); + + if( aNetItemTst->m_Type == NET_PIN && aNetItemTst->m_Link ) + alt_cmp = aNetItemTst->GetComponentParent()->GetRef( &aNetItemTst->m_SheetPath ); + + msg.Printf( _( "Pin %s (%s) of component %s is connected to " ), + GetChars( string_pinnum ), + GetChars( LIB_PIN::GetElectricalTypeName( ii ) ), + GetChars( cmp_ref ) ); + marker->SetData( errortype, aNetItemRef->m_Start, msg, aNetItemRef->m_Start ); + msg.Printf( _( "pin %s (%s) of component %s (net %d)." ), + GetChars( alt_string_pinnum ), + GetChars( LIB_PIN::GetElectricalTypeName( jj ) ), + GetChars( alt_cmp ), + aNetItemRef->GetNet() ); + marker->SetAuxiliaryData( msg, aNetItemTst->m_Start ); + } +} + + +void TestOthersItems( NETLIST_OBJECT_LIST* aList, + unsigned aNetItemRef, unsigned aNetStart, + int* aMinConnexion ) +{ + unsigned netItemTst = aNetStart; + int jj; + int erc = OK; + + /* Analysis of the table of connections. */ + int ref_elect_type = aList->GetItem( aNetItemRef )->m_ElectricalType; + int local_minconn = NOC; + + if( ref_elect_type == PIN_NC ) + local_minconn = NPI; + + /* Test pins connected to NetItemRef */ + for( ; ; netItemTst++ ) + { + if( aNetItemRef == netItemTst ) + continue; + + // We examine only a given net. We stop the search if the net changes + if( ( netItemTst >= aList->size() ) // End of list + || ( aList->GetItemNet( aNetItemRef ) != + aList->GetItemNet( netItemTst ) ) ) // End of net + { + /* End net code found: minimum connection test. */ + if( ( *aMinConnexion < NET_NC ) && ( local_minconn < NET_NC ) ) + { + /* Not connected or not driven pin. */ + bool seterr = true; + + if( local_minconn == NOC && + aList->GetItemType( aNetItemRef ) == NET_PIN ) + { + /* This pin is not connected: for multiple part per + * package, and duplicated pin, + * search for an other instance of this pin + * this will be flagged only if all instances of this pin + * are not connected + * TODO test also if instances connected are connected to + * the same net + */ + for( unsigned duplicate = 0; duplicate < aList->size(); duplicate++ ) + { + if( aList->GetItemType( duplicate ) != NET_PIN ) + continue; + + if( duplicate == aNetItemRef ) + continue; + + if( aList->GetItem( aNetItemRef )->m_PinNum != + aList->GetItem( duplicate )->m_PinNum ) + continue; + + if( ( (SCH_COMPONENT*) aList->GetItem( aNetItemRef )-> + m_Link )->GetRef( &aList->GetItem( aNetItemRef )-> m_SheetPath ) != + ( (SCH_COMPONENT*) aList->GetItem( duplicate )->m_Link ) + ->GetRef( &aList->GetItem( duplicate )->m_SheetPath ) ) + continue; + + // Same component and same pin. Do dot create error for this pin + // if the other pin is connected (i.e. if duplicate net has an other + // item) + if( (duplicate > 0) + && ( aList->GetItemNet( duplicate ) == + aList->GetItemNet( duplicate - 1 ) ) ) + seterr = false; + + if( (duplicate < aList->size() - 1) + && ( aList->GetItemNet( duplicate ) == + aList->GetItemNet( duplicate + 1 ) ) ) + seterr = false; + } + } + + if( seterr ) + Diagnose( aList->GetItem( aNetItemRef ), NULL, local_minconn, WAR ); + + *aMinConnexion = DRV; // inhibiting other messages of this + // type for the net. + } + return; + } + + switch( aList->GetItemType( netItemTst ) ) + { + case NET_ITEM_UNSPECIFIED: + case NET_SEGMENT: + case NET_BUS: + case NET_JUNCTION: + case NET_LABEL: + case NET_HIERLABEL: + case NET_BUSLABELMEMBER: + case NET_HIERBUSLABELMEMBER: + case NET_SHEETBUSLABELMEMBER: + case NET_SHEETLABEL: + case NET_GLOBLABEL: + case NET_GLOBBUSLABELMEMBER: + case NET_PINLABEL: + break; + + case NET_NOCONNECT: + local_minconn = std::max( NET_NC, local_minconn ); + break; + + case NET_PIN: + jj = aList->GetItem( netItemTst )->m_ElectricalType; + local_minconn = std::max( MinimalReq[ref_elect_type][jj], local_minconn ); + + if( netItemTst <= aNetItemRef ) + break; + + if( erc == OK ) + { + erc = DiagErc[ref_elect_type][jj]; + + if( erc != OK ) + { + if( aList->GetConnectionType( netItemTst ) == UNCONNECTED ) + { + Diagnose( aList->GetItem( aNetItemRef ), + aList->GetItem( netItemTst ), + 0, erc ); + aList->SetConnectionType( netItemTst, NOCONNECT_SYMBOL_PRESENT ); + } + } + } + + break; + } + } +} + + +int CountPinsInNet( NETLIST_OBJECT_LIST* aList, unsigned aNetStart ) +{ + int count = 0; + int curr_net = aList->GetItemNet( aNetStart ); + + /* Test pins connected to NetItemRef */ + for( unsigned item = aNetStart; item < aList->size(); item++ ) + { + // We examine only a given net. We stop the search if the net changes + if( curr_net != aList->GetItemNet( item ) ) // End of net + break; + + if( aList->GetItemType( item ) == NET_PIN ) + count++; + } + + return count; +} + +bool WriteDiagnosticERC( const wxString& aFullFileName ) +{ + wxString msg; + + wxFFile file( aFullFileName, wxT( "wt" ) ); + + if( !file.IsOpened() ) + return false; + + msg = _( "ERC report" ); + msg << wxT(" (") << DateAndTime() << wxT( ", " ) + << _( "Encoding UTF8" ) << wxT( " )\n" ); + + int err_count = 0; + int warn_count = 0; + int total_count = 0; + SCH_SHEET_LIST sheetList; + SCH_SHEET_PATH* sheet; + + for( sheet = sheetList.GetFirst(); sheet != NULL; sheet = sheetList.GetNext() ) + { + msg << wxString::Format( _( "\n***** Sheet %s\n" ), + GetChars( sheet->PathHumanReadable() ) ); + + for( SCH_ITEM* item = sheet->LastDrawList(); item != NULL; item = item->Next() ) + { + if( item->Type() != SCH_MARKER_T ) + continue; + + SCH_MARKER* marker = (SCH_MARKER*) item; + + if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC ) + continue; + + total_count++; + + if( marker->GetErrorLevel() == MARKER_BASE::MARKER_SEVERITY_ERROR ) + err_count++; + + if( marker->GetErrorLevel() == MARKER_BASE::MARKER_SEVERITY_WARNING ) + warn_count++; + + msg << marker->GetReporter().ShowReport(); + } + } + + msg << wxString::Format( _( "\n ** ERC messages: %d Errors %d Warnings %d\n" ), + total_count, err_count, warn_count ); + + // Currently: write report unsing UTF8 (as usual in Kicad). + // TODO: see if we can use the current encoding page (mainly for Windows users), + // Or other format (HTML?) + file.Write( msg ); + + // wxFFile dtor will close the file. + + return true; +} + + +void TestLabel( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aStartNet ) +{ + unsigned netItemTst = aStartNet; + int erc = 1; + + // Review the list of labels connected to NetItemRef: + for( ; ; netItemTst++ ) + { + if( netItemTst == aNetItemRef ) + continue; + + /* Is always in the same net? */ + if( ( netItemTst == aList->size() ) + || ( aList->GetItemNet( aNetItemRef ) != aList->GetItemNet( netItemTst ) ) ) + { + /* End Netcode found. */ + if( erc ) + { + /* Glabel or SheetLabel orphaned. */ + Diagnose( aList->GetItem( aNetItemRef ), NULL, -1, WAR ); + } + + return; + } + + if( aList->GetItem( aNetItemRef )->IsLabelConnected( aList->GetItem( netItemTst ) ) ) + erc = 0; + + //same thing, different order. + if( aList->GetItem( netItemTst )->IsLabelConnected( aList->GetItem( aNetItemRef ) ) ) + erc = 0; + } +} diff --git a/eeschema/erc.h b/eeschema/erc.h new file mode 100644 index 00000000..708fb6a4 --- /dev/null +++ b/eeschema/erc.h @@ -0,0 +1,127 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2009-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file erc.h + */ + +#ifndef _ERC_H +#define _ERC_H + + +class EDA_DRAW_PANEL; +class NETLIST_OBJECT; +class NETLIST_OBJECT_LIST; + +/* For ERC markers: error types (used in diags, and to set the color): +*/ +enum errortype +{ + OK = 0, + WAR, // Error: severity = warning + ERR, // Error: severity = error + UNC // Error: unconnected pin +}; + +extern const wxString CommentERC_H[]; +extern const wxString CommentERC_V[]; + +/// DRC error codes: +#define ERCE_UNSPECIFIED 0 +#define ERCE_DUPLICATE_SHEET_NAME 1 // duplicate sheet names within a given sheet +#define ERCE_PIN_NOT_CONNECTED 2 // pin not connected and not no connect symbol +#define ERCE_PIN_NOT_DRIVEN 3 // pin connected to some others pins but no pin to drive it +#define ERCE_PIN_TO_PIN_WARNING 4 // pin connected to an other pin: warning level +#define ERCE_PIN_TO_PIN_ERROR 5 // pin connected to an other pin: error level +#define ERCE_HIERACHICAL_LABEL 6 // mismatch between hierarchical labels and pins sheets +#define ERCE_NOCONNECT_CONNECTED 7 // a no connect symbol is connected to more than 1 pin +#define ERCE_GLOBLABEL 8 // global label not connected to any other global label + +/* Minimal connection table */ +#define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C. +#define DRV 3 // Net driven by a signal (a pin output for instance) +#define NET_NC 2 // Net "connected" to a "NoConnect symbol" +#define NOD 1 // Net not driven ( Such as 2 or more connected inputs ) +#define NOC 0 // initial state of a net: no connection + + +/** + * Function WriteDiagnosticERC + * save the ERC errors to \a aFullFileName. + * + * @param aFullFileName A wxString object containing the file name and path. + */ +extern bool WriteDiagnosticERC( const wxString& aFullFileName ); + +/** + * Performs ERC testing and creates an ERC marker to show the ERC problem for aNetItemRef + * or between aNetItemRef and aNetItemTst. + * if MinConn < 0: this is an error on labels + */ +extern void Diagnose( NETLIST_OBJECT* NetItemRef, NETLIST_OBJECT* NetItemTst, + int MinConnexion, int Diag ); + +/** + * Perform ERC testing for electrical conflicts between \a NetItemRef and other items + * (mainly pin) on the same net. + * @param aList = a reference to the list of connected objects + * @param aNetItemRef = index in list of the current object + * @param aNetStart = index in list of net objects of the first item + * @param aMinConnexion = a pointer to a variable to store the minimal connection + * found( NOD, DRV, NPI, NET_NC) + */ +extern void TestOthersItems( NETLIST_OBJECT_LIST* aList, + unsigned aNetItemRef, unsigned aNetStart, + int* aMinConnexion ); + +/** + * Counts number of pins connected on the same net. + * Used to find all pins conected to a no connect symbol + * @return the pin count of the net starting at aNetStart + * @param aNetStart = index in list of net objects of the first item + * @param aList = a reference to the list of connected objects + */ +int CountPinsInNet( NETLIST_OBJECT_LIST* aList, unsigned aNetStart ); + + +/** + * Function TestLabel + * performs an ERC on a sheet labels to verify that it is connected to a corresponding + * sub sheet global label. + */ +extern void TestLabel( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aStartNet ); + +/** + * Function TestDuplicateSheetNames( ) + * inside a given sheet, one cannot have sheets with duplicate names (file + * names can be duplicated). + * @return the error count + * @param aCreateMarker: true = create error markers in schematic, + * false = calculate error count only + */ +extern int TestDuplicateSheetNames( bool aCreateMarker ); + + +#endif // _ERC_H diff --git a/eeschema/events_called_functions_for_edit.cpp b/eeschema/events_called_functions_for_edit.cpp new file mode 100644 index 00000000..bc7c69ac --- /dev/null +++ b/eeschema/events_called_functions_for_edit.cpp @@ -0,0 +1,79 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 + */ + +/* + * @file events_called_functions.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +void SCH_EDIT_FRAME::OnCopySchematicItemRequest( wxCommandEvent& event ) +{ + SCH_ITEM * curr_item = GetScreen()->GetCurItem(); + + if( !curr_item || curr_item->GetFlags() ) + return; + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + switch( curr_item->Type() ) + { + case SCH_COMPONENT_T: + { + SCH_COMPONENT* newitem; + newitem = new SCH_COMPONENT( *( (SCH_COMPONENT*) curr_item ) ); + newitem->SetTimeStamp( GetNewTimeStamp() ); + newitem->ClearAnnotation( NULL ); + newitem->SetFlags( IS_NEW ); + // Draw the new part, MoveItem() expects it to be already on screen. + newitem->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( newitem, &dc ); + } + break; + + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + { + SCH_TEXT* newitem = (SCH_TEXT*) curr_item->Clone(); + newitem->SetFlags( IS_NEW ); + // Draw the new item, MoveItem() expects it to be already on screen. + newitem->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( newitem, &dc ); + } + break; + + default: + break; + } +} diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp new file mode 100644 index 00000000..81b6d692 --- /dev/null +++ b/eeschema/files-io.cpp @@ -0,0 +1,547 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 2013 CERN (www.cern.ch) + * Copyright (C) 1992-2015 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 + */ + +/** + * @file eeschema/files-io.cpp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName, bool aCreateBackupFile ) +{ + wxString msg; + wxFileName schematicFileName; + bool success; + + if( aScreen == NULL ) + aScreen = GetScreen(); + + // If no name exists in the window yet - save as new. + if( aScreen->GetFileName().IsEmpty() ) + aSaveUnderNewName = true; + + // Construct the name of the file to be saved + schematicFileName = Prj().AbsolutePath( aScreen->GetFileName() ); + + if( aSaveUnderNewName ) + { + wxFileDialog dlg( this, _( "Schematic Files" ), + wxPathOnly( Prj().GetProjectFullName() ), + schematicFileName.GetFullName(), SchematicFileWildcard, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + schematicFileName = dlg.GetPath(); + + if( schematicFileName.GetExt() != SchematicFileExtension ) + schematicFileName.SetExt( SchematicFileExtension ); + } + + if( !IsWritable( schematicFileName ) ) + return false; + + // Create backup if requested + if( aCreateBackupFile && schematicFileName.FileExists() ) + { + wxFileName backupFileName = schematicFileName; + + // Rename the old file to a '.bak' one: + backupFileName.SetExt( SchematicBackupFileExtension ); + + if( backupFileName.FileExists() ) + wxRemoveFile( backupFileName.GetFullPath() ); + + if( !wxRenameFile( schematicFileName.GetFullPath(), backupFileName.GetFullPath() ) ) + { + msg.Printf( _( "Could not save backup of file '%s'" ), + GetChars( schematicFileName.GetFullPath() ) ); + DisplayError( this, msg ); + } + } + + // Save + wxLogTrace( traceAutoSave, + wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) ); + + FILE* f = wxFopen( schematicFileName.GetFullPath(), wxT( "wt" ) ); + + if( !f ) + { + msg.Printf( _( "Failed to create file '%s'" ), + GetChars( schematicFileName.GetFullPath() ) ); + DisplayError( this, msg ); + return false; + } + + success = aScreen->Save( f ); + + if( success ) + { + // Delete auto save file. + wxFileName autoSaveFileName = schematicFileName; + autoSaveFileName.SetName( AUTOSAVE_PREFIX_FILENAME + schematicFileName.GetName() ); + + if( autoSaveFileName.FileExists() ) + { + wxLogTrace( traceAutoSave, + wxT( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() + + wxT( ">" ) ); + + wxRemoveFile( autoSaveFileName.GetFullPath() ); + } + + // Update the screen and frame info. + if( aSaveUnderNewName ) + aScreen->SetFileName( schematicFileName.GetFullPath() ); + aScreen->ClrSave(); + aScreen->ClrModify(); + + msg.Printf( _( "File %s saved" ), GetChars( aScreen->GetFileName() ) ); + SetStatusText( msg, 0 ); + } + else + { + DisplayError( this, _( "File write operation failed." ) ); + } + + fclose( f ); + + return success; +} + + +void SCH_EDIT_FRAME::Save_File( wxCommandEvent& event ) +{ + int id = event.GetId(); + + switch( id ) + { + case ID_UPDATE_ONE_SHEET: + SaveEEFile( NULL ); + break; + + case ID_SAVE_ONE_SHEET_UNDER_NEW_NAME: + if( SaveEEFile( NULL, true ) ) + { + CreateArchiveLibraryCacheFile( true ); + } + break; + } + + UpdateTitle(); +} + + +bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) +{ + // implement the pseudo code from KIWAY_PLAYER.h: + + SCH_SCREENS screenList; + + // This is for python: + if( aFileSet.size() != 1 ) + { + UTF8 msg = StrPrintf( "Eeschema:%s() takes only a single filename", __func__ ); + DisplayError( this, msg ); + return false; + } + + wxString fullFileName( aFileSet[0] ); + + // We insist on caller sending us an absolute path, if it does not, we say it's a bug. + wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), + wxT( "bug in single_top.cpp or project manager." ) ); + + if( !LockFile( fullFileName ) ) + { + wxString msg = wxString::Format( _( + "Schematic file '%s' is already open." ), + GetChars( fullFileName ) + ); + DisplayError( this, msg ); + return false; + } + + // save any currently open and modified project files. + for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() ) + { + if( screen->IsModify() ) + { + int response = YesNoCancelDialog( this, _( + "The current schematic has been modified. Do you wish to save the changes?" ), + wxEmptyString, + _( "Save and Load" ), + _( "Load Without Saving" ) + ); + + if( response == wxID_CANCEL ) + { + return false; + } + else if( response == wxID_YES ) + { + wxCommandEvent dummy; + OnSaveProject( dummy ); + } + else + { + // response == wxID_NO, fall thru + } + break; + } + } + + wxFileName pro = fullFileName; + pro.SetExt( ProjectFileExtension ); + + bool is_new = !wxFileName::IsFileReadable( fullFileName ); + + // If its a non-existent schematic and caller thinks it exists + if( is_new && !( aCtl & KICTL_CREATE ) ) + { + // notify user that fullFileName does not exist, ask if user wants to create it. + wxString ask = wxString::Format( _( + "Schematic '%s' does not exist. Do you wish to create it?" ), + GetChars( fullFileName ) + ); + if( !IsOK( this, ask ) ) + return false; + } + + // unload current project file before loading new + { + delete g_RootSheet; + g_RootSheet = NULL; + + CreateScreens(); + } + + GetScreen()->SetFileName( fullFileName ); + g_RootSheet->SetFileName( fullFileName ); + + SetStatusText( wxEmptyString ); + ClearMsgPanel(); + + wxString msg = wxString::Format( _( + "Ready\nProject dir: '%s'\n" ), + GetChars( wxPathOnly( Prj().GetProjectFullName() ) ) + ); + SetStatusText( msg ); + + // PROJECT::SetProjectFullName() is an impactful function. It should only be + // called under carefully considered circumstances. + + // The calling code should know not to ask me here to change projects unless + // it knows what consequences that will have on other KIFACEs running and using + // this same PROJECT. It can be very harmful if that calling code is stupid. + Prj().SetProjectFullName( pro.GetFullPath() ); + + LoadProjectFile(); + + // load the libraries here, not in SCH_SCREEN::Draw() which is a context + // that will not tolerate DisplayError() dialog since we're already in an + // event handler in there. + // And when a schematic file is loaded, we need these libs to initialize + // some parameters (links to PART LIB, dangling ends ...) + Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL ); + Prj().SchLibs(); + + if( is_new ) + { + // mark new, unsaved file as modified. + GetScreen()->SetModify(); + } + else + { + g_RootSheet->SetScreen( NULL ); + + DBG( printf( "%s: loading schematic %s\n", __func__, TO_UTF8( fullFileName ) );) + + bool diag = g_RootSheet->Load( this ); + (void) diag; + + SetScreen( m_CurrentSheet->LastScreen() ); + + GetScreen()->ClrModify(); + + UpdateFileHistory( fullFileName ); + + // Check to see whether some old library parts need to be rescued + // Only do this if RescueNeverShow was not set. + wxConfigBase *config = Kiface().KifaceSettings(); + bool rescueNeverShow = false; + config->Read( RESCUE_NEVER_SHOW_KEY, &rescueNeverShow, false ); + + if( !rescueNeverShow ) + { + if( RescueProject( false ) ) + { + GetScreen()->CheckComponentsToPartsLinks(); + GetScreen()->TestDanglingEnds(); + } + } + } + + GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); + Zoom_Automatique( false ); + SetSheetNumberAndCount(); + + m_canvas->Refresh( true ); + + return true; +} + + +bool SCH_EDIT_FRAME::AppendOneEEProject() +{ + wxString fullFileName; + + SCH_SCREEN* screen = GetScreen(); + + if( !screen ) + { + wxLogError( wxT("Document not ready, cannot import") ); + return false; + } + + // open file chooser dialog + wxString path = wxPathOnly( Prj().GetProjectFullName() ); + + wxFileDialog dlg( this, _( "Import Schematic" ), path, + wxEmptyString, SchematicFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + fullFileName = dlg.GetPath(); + + wxFileName fn = fullFileName; + + if( fn.IsRelative() ) + { + fn.MakeAbsolute(); + fullFileName = fn.GetFullPath(); + } + + wxString cache_name = PART_LIBS::CacheName( fullFileName ); + if( !!cache_name ) + { + PART_LIBS* libs = Prj().SchLibs(); + + if( PART_LIB* lib = libs->AddLibrary( cache_name ) ) + lib->SetCache(); + } + + wxLogDebug( wxT( "Importing schematic " ) + fullFileName ); + + // Keep trace of the last item in list. + // New items will be loaded after this one. + SCH_ITEM* bs = screen->GetDrawItems(); + + if( bs ) + while( bs->Next() ) + bs = bs->Next(); + + // load the project + bool success = LoadOneEEFile( screen, fullFileName, true ); + + if( success ) + { + // the new loaded items need cleaning to avoid duplicate parameters + // which should be unique (ref and time stamp). + // Clear ref and set a new time stamp for new items + if( bs == NULL ) + bs = screen->GetDrawItems(); + else + bs = bs->Next(); + + while( bs ) + { + SCH_ITEM* nextbs = bs->Next(); + + // To avoid issues with the current hieratchy, + // do not load included sheets files and give new filenames + // and new sheet names. + // There are many tricky cases (loops, creation of complex hierarchies + // with duplicate file names, duplicate sheet names...) + // So the included sheets names are renamed if existing, + // and filenames are just renamed to avoid loops and + // creation of complex hierarchies. + // If someone want to change it for a better append function, remember + // these cases need work to avoid issues. + if( bs->Type() == SCH_SHEET_T ) + { + SCH_SHEET * sheet = (SCH_SHEET *) bs; + time_t newtimestamp = GetNewTimeStamp(); + sheet->SetTimeStamp( newtimestamp ); + + // Check for existing subsheet name in the current sheet + wxString tmp = sheet->GetName(); + sheet->SetName( wxEmptyString ); + const SCH_SHEET* subsheet = GetScreen()->GetSheet( tmp ); + + if( subsheet ) + sheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ), (long) newtimestamp ) ); + else + sheet->SetName( tmp ); + + sheet->SetFileName( wxString::Format( wxT( "file%8.8lX.sch" ), (long) newtimestamp ) ); + SCH_SCREEN* screen = new SCH_SCREEN( &Kiway() ); + screen->SetMaxUndoItems( m_UndoRedoCountMax ); + sheet->SetScreen( screen ); + sheet->GetScreen()->SetFileName( sheet->GetFileName() ); + } + // clear annotation and init new time stamp for the new components + else if( bs->Type() == SCH_COMPONENT_T ) + { + ( (SCH_COMPONENT*) bs )->SetTimeStamp( GetNewTimeStamp() ); + ( (SCH_COMPONENT*) bs )->ClearAnnotation( NULL ); + + // Clear flags, which are set by these previous modifications: + bs->ClearFlags(); + } + + bs = nextbs; + } + } + + OnModify(); + + // redraw base screen (ROOT) if necessary + GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); + Zoom_Automatique( false ); + SetSheetNumberAndCount(); + m_canvas->Refresh( true ); + return success; +} + + +void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event ) +{ + wxString msg = _( "This operation cannot be undone. " + "Besides, take into account that hierarchical sheets will not be appended.\n\n" + "Do you want to save the current document before proceeding?" ); + + if( IsOK( this, msg ) ) + OnSaveProject( event ); + + AppendOneEEProject(); +} + + +void SCH_EDIT_FRAME::OnSaveProject( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen; + SCH_SCREENS screenList; + + // I want to see it in the debugger, show me the string! Can't do that with wxFileName. + wxString fileName = Prj().AbsolutePath( g_RootSheet->GetFileName() ); + + wxFileName fn = fileName; + + if( !fn.IsDirWritable() ) + { + wxString msg = wxString::Format( _( + "Directory '%s' is not writable" ), + GetChars( fn.GetPath() ) + ); + + DisplayError( this, msg ); + return; + } + + for( screen = screenList.GetFirst(); screen; screen = screenList.GetNext() ) + SaveEEFile( screen ); + + CreateArchiveLibraryCacheFile(); + + UpdateTitle(); +} + + +bool SCH_EDIT_FRAME::doAutoSave() +{ + wxFileName tmpFileName = g_RootSheet->GetFileName(); + wxFileName fn = tmpFileName; + wxFileName tmp; + SCH_SCREENS screens; + + bool autoSaveOk = true; + + tmp.AssignDir( fn.GetPath() ); + + if( !tmp.IsOk() ) + return false; + + if( !IsWritable( tmp ) ) + return false; + + for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() ) + { + // Only create auto save files for the schematics that have been modified. + if( !screen->IsSave() ) + continue; + + tmpFileName = fn = screen->GetFileName(); + + // Auto save file name is the normal file name prefixed with AUTOSAVE_PREFIX_FILENAME. + fn.SetName( AUTOSAVE_PREFIX_FILENAME + fn.GetName() ); + + screen->SetFileName( fn.GetFullPath() ); + + if( SaveEEFile( screen, false, NO_BACKUP_FILE ) ) + screen->SetModify(); + else + autoSaveOk = false; + + screen->SetFileName( tmpFileName.GetFullPath() ); + } + + if( autoSaveOk ) + m_autoSaveState = false; + + return autoSaveOk; +} diff --git a/eeschema/find.cpp b/eeschema/find.cpp new file mode 100644 index 00000000..5109acd3 --- /dev/null +++ b/eeschema/find.cpp @@ -0,0 +1,515 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema/find.cpp + * @brief Functions for searching for a schematic item. + */ + +/* + * Search a text (text, value, reference) within a component or + * search a component in libraries, a marker ..., + * in current sheet or whole the project + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + + +void SCH_EDIT_FRAME::OnFindDrcMarker( wxFindDialogEvent& event ) +{ + static SCH_MARKER* lastMarker = NULL; + + wxString msg; + SCH_SHEET_LIST schematic; + SCH_SHEET_PATH* sheetFoundIn = NULL; + bool wrap = ( event.GetFlags() & FR_SEARCH_WRAP ) != 0; + bool warpCursor = ( ( event.GetId() == wxEVT_COMMAND_FIND_CLOSE ) || + !( event.GetFlags() & FR_NO_WARP_CURSOR ) ); + + if( event.GetFlags() & FR_CURRENT_SHEET_ONLY ) + { + sheetFoundIn = m_CurrentSheet; + lastMarker = (SCH_MARKER*) m_CurrentSheet->FindNextItem( SCH_MARKER_T, lastMarker, wrap ); + } + else + { + lastMarker = (SCH_MARKER*) schematic.FindNextItem( SCH_MARKER_T, &sheetFoundIn, + lastMarker, wrap ); + } + + if( lastMarker != NULL ) + { + if( *sheetFoundIn != *m_CurrentSheet ) + { + sheetFoundIn->LastScreen()->SetZoom( GetScreen()->GetZoom() ); + *m_CurrentSheet = *sheetFoundIn; + m_CurrentSheet->UpdateAllScreenReferences(); + } + + SetCrossHairPosition( lastMarker->GetPosition() ); + + RedrawScreen( lastMarker->GetPosition(), warpCursor ); + + wxString path = sheetFoundIn->Path(); + wxString units = GetAbbreviatedUnitsLabel(); + double x = To_User_Unit( g_UserUnit, (double) lastMarker->GetPosition().x ); + double y = To_User_Unit( g_UserUnit, (double) lastMarker->GetPosition().y ); + msg.Printf( _( "Design rule check marker found in sheet %s at %0.3f%s, %0.3f%s" ), + GetChars( path ), x, GetChars( units ), y, GetChars( units) ); + SetStatusText( msg ); + } + else + { + SetStatusText( _( "No more markers were found." ) ); + } +} + + +SCH_ITEM* SCH_EDIT_FRAME::FindComponentAndItem( const wxString& aReference, + bool aSearchHierarchy, + SCH_SEARCH_T aSearchType, + const wxString& aSearchText, + bool aWarpMouse ) +{ + SCH_SHEET_PATH* sheet; + SCH_SHEET_PATH* sheetWithComponentFound = NULL; + SCH_ITEM* item = NULL; + SCH_COMPONENT* Component = NULL; + wxPoint pos; + bool centerAndRedraw = false; + bool notFound = true; + LIB_PIN* pin; + SCH_SHEET_LIST sheetList; + + sheet = sheetList.GetFirst(); + + if( !aSearchHierarchy ) + sheet = m_CurrentSheet; + + for( ; sheet != NULL; sheet = sheetList.GetNext() ) + { + item = sheet->LastDrawList(); + + for( ; ( item != NULL ) && ( notFound == true ); item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + SCH_COMPONENT* pSch = (SCH_COMPONENT*) item; + + if( aReference.CmpNoCase( pSch->GetRef( sheet ) ) == 0 ) + { + Component = pSch; + sheetWithComponentFound = sheet; + + switch( aSearchType ) + { + default: + case FIND_COMPONENT_ONLY: // Find component only + notFound = false; + pos = pSch->GetPosition(); + break; + + case FIND_PIN: // find a pin + pos = pSch->GetPosition(); // temporary: will be changed if the pin is found. + pin = pSch->GetPin( aSearchText ); + + if( pin == NULL ) + break; + + notFound = false; + pos += pin->GetPosition(); + break; + + case FIND_REFERENCE: // find reference + notFound = false; + pos = pSch->GetField( REFERENCE )->GetPosition(); + break; + + case FIND_VALUE: // find value + pos = pSch->GetPosition(); + + if( aSearchText.CmpNoCase( pSch->GetField( VALUE )->GetShownText() ) != 0 ) + break; + + notFound = false; + pos = pSch->GetField( VALUE )->GetPosition(); + break; + } + } + } + + if( (aSearchHierarchy == false) || (notFound == false) ) + break; + } + + if( Component ) + { + sheet = sheetWithComponentFound; + + if( *sheet != *m_CurrentSheet ) + { + sheet->LastScreen()->SetZoom( GetScreen()->GetZoom() ); + *m_CurrentSheet = *sheet; + m_CurrentSheet->UpdateAllScreenReferences(); + centerAndRedraw = true; + } + + wxPoint delta; + pos -= Component->GetPosition(); + delta = Component->GetTransform().TransformCoordinate( pos ); + pos = delta + Component->GetPosition(); + + + /* There may be need to reframe the drawing */ + if( ! m_canvas->IsPointOnDisplay( pos ) ) + { + centerAndRedraw = true; + } + + if( centerAndRedraw ) + { + SetCrossHairPosition( pos ); + RedrawScreen( pos, aWarpMouse ); + } + + else + { + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + m_canvas->CrossHairOff( &dc ); + + if( aWarpMouse ) + m_canvas->MoveCursor( pos ); + + SetCrossHairPosition( pos ); + + m_canvas->CrossHairOn( &dc ); + } + } + + + /* Print diag */ + wxString msg_item; + wxString msg; + + switch( aSearchType ) + { + default: + case FIND_COMPONENT_ONLY: // Find component only + msg_item = _( "component" ); + break; + + case FIND_PIN: // find a pin + msg_item.Printf( _( "pin %s" ), GetChars( aSearchText ) ); + break; + + case FIND_REFERENCE: // find reference + msg_item.Printf( _( "reference %s" ), GetChars( aSearchText ) ); + break; + + case FIND_VALUE: // find value + msg_item.Printf( _( "value %s" ), GetChars( aSearchText ) ); + break; + + case FIND_FIELD: // find field. todo + msg_item.Printf( _( "field %s" ), GetChars( aSearchText ) ); + break; + } + + if( Component ) + { + if( !notFound ) + { + msg.Printf( _( "%s %s found" ), + GetChars( aReference ), GetChars( msg_item ) ); + } + else + { + msg.Printf( _( "%s found but %s not found" ), + GetChars( aReference ), GetChars( msg_item ) ); + } + } + else + { + msg.Printf( _( "Component %s not found" ), + GetChars( aReference ) ); + } + + SetStatusText( msg ); + + return item; +} + + +bool SCH_EDIT_FRAME::IsSearchCacheObsolete( const SCH_FIND_REPLACE_DATA& aSearchCriteria ) +{ + PART_LIBS* libs = Prj().SchLibs(); + int mod_hash = libs->GetModifyHash(); + + // the cache is obsolete whenever any library changes. + if( mod_hash != m_foundItems.GetLibHash() ) + { + m_foundItems.SetForceSearch(); + m_foundItems.SetLibHash( mod_hash ); + return true; + } + else if( m_foundItems.IsSearchRequired( aSearchCriteria ) ) + return true; + else + return false; +} + + +void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent ) +{ + SCH_FIND_REPLACE_DATA searchCriteria; + SCH_FIND_COLLECTOR_DATA data; + + searchCriteria.SetFlags( aEvent.GetFlags() ); + searchCriteria.SetFindString( aEvent.GetFindString() ); + searchCriteria.SetReplaceString( aEvent.GetReplaceString() ); + + if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_CLOSE ) + { + if( m_foundItems.GetCount() == 0 ) + return; + + // Refresh the search cache in case something has changed. This prevents any stale + // pointers from crashing Eeschema when the wxEVT_FIND_CLOSE event is handled. + if( IsSearchCacheObsolete( searchCriteria ) ) + { + if( aEvent.GetFlags() & FR_CURRENT_SHEET_ONLY && g_RootSheet->CountSheets() > 1 ) + { + m_foundItems.Collect( searchCriteria, m_CurrentSheet ); + } + else + { + m_foundItems.Collect( searchCriteria ); + } + } + } + else if( IsSearchCacheObsolete( searchCriteria ) ) + { + if( aEvent.GetFlags() & FR_CURRENT_SHEET_ONLY && g_RootSheet->CountSheets() > 1 ) + { + m_foundItems.Collect( searchCriteria, m_CurrentSheet ); + } + else + { + m_foundItems.Collect( searchCriteria ); + } + } + else + { + EDA_ITEM* currentItem = m_foundItems.GetItem( data ); + + if( currentItem != NULL ) + currentItem->SetForceVisible( false ); + + m_foundItems.UpdateIndex(); + } + + updateFindReplaceView( aEvent ); +} + + +void SCH_EDIT_FRAME::OnFindReplace( wxFindDialogEvent& aEvent ) +{ + static int nextFoundIndex = 0; + SCH_ITEM* item; + SCH_SHEET_PATH* sheet; + SCH_SHEET_LIST schematic; + SCH_FIND_COLLECTOR_DATA data; + SCH_FIND_REPLACE_DATA searchCriteria; + + searchCriteria.SetFlags( aEvent.GetFlags() ); + searchCriteria.SetFindString( aEvent.GetFindString() ); + searchCriteria.SetReplaceString( aEvent.GetReplaceString() ); + m_foundItems.SetReplaceString( aEvent.GetReplaceString() ); + + if( IsSearchCacheObsolete( searchCriteria ) ) + { + if( aEvent.GetFlags() & FR_CURRENT_SHEET_ONLY && g_RootSheet->CountSheets() > 1 ) + { + m_foundItems.Collect( searchCriteria, m_CurrentSheet ); + } + else + { + m_foundItems.Collect( searchCriteria ); + } + + // Restore the next found index on cache refresh. Prevents single replace events + // from starting back at the beginning of the cache. + m_foundItems.SetFoundIndex( nextFoundIndex ); + } + + if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL ) + { + while( ( item = (SCH_ITEM*) m_foundItems.GetItem( data ) ) != NULL ) + { + SCH_ITEM* undoItem = data.GetParent(); + + // Don't save child items in undo list. + if( undoItem == NULL ) + undoItem = item; + + SetUndoItem( undoItem ); + + sheet = schematic.GetSheetByPath( data.GetSheetPath() ); + + wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + data.GetSheetPath() ); + + if( m_foundItems.ReplaceItem( sheet ) ) + { + OnModify(); + SaveUndoItemInUndoList( undoItem ); + updateFindReplaceView( aEvent ); + } + + m_foundItems.IncrementIndex(); + + if( m_foundItems.PassedEnd() ) + break; + } + } + else + { + item = (SCH_ITEM*) m_foundItems.GetItem( data ); + + wxCHECK_RET( item != NULL, wxT( "Invalid replace item in find collector list." ) ); + + SCH_ITEM* undoItem = data.GetParent(); + + if( undoItem == NULL ) + undoItem = item; + + SetUndoItem( undoItem ); + + sheet = schematic.GetSheetByPath( data.GetSheetPath() ); + + wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + data.GetSheetPath() ); + + if( m_foundItems.ReplaceItem( sheet ) ) + { + OnModify(); + SaveUndoItemInUndoList( undoItem ); + updateFindReplaceView( aEvent ); + } + + m_foundItems.IncrementIndex(); + nextFoundIndex = m_foundItems.GetFoundIndex(); + } + + // End the replace if we are at the end if the list. This prevents an infinite loop if + // wrap search is selected and all of the items have been replaced with a value that + // still satisfies the search criteria. + if( m_foundItems.PassedEnd() ) + aEvent.SetFlags( aEvent.GetFlags() & ~FR_REPLACE_ITEM_FOUND ); +} + + +void SCH_EDIT_FRAME::updateFindReplaceView( wxFindDialogEvent& aEvent ) +{ + wxString msg; + SCH_SHEET_LIST schematic; + SCH_FIND_COLLECTOR_DATA data; + SCH_FIND_REPLACE_DATA searchCriteria; + bool warpCursor = !( aEvent.GetFlags() & FR_NO_WARP_CURSOR ); + + searchCriteria.SetFlags( aEvent.GetFlags() ); + searchCriteria.SetFindString( aEvent.GetFindString() ); + searchCriteria.SetReplaceString( aEvent.GetReplaceString() ); + + if( m_foundItems.GetItem( data ) != NULL ) + { + wxLogTrace( traceFindReplace, wxT( "Found " ) + m_foundItems.GetText() ); + + SCH_SHEET_PATH* sheet = schematic.GetSheetByPath( data.GetSheetPath() ); + + wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + + data.GetSheetPath() ); + + SCH_ITEM* item = (SCH_ITEM*)m_foundItems.GetItem( data ); + + // Make the item temporarily visible just in case it's hide flag is set. This + // has no effect on objects that don't support hiding. If this is a close find + // dialog event, clear the temporary visibility flag. + if( item ) + { + if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_CLOSE ) + item->SetForceVisible( false ); + else if( item->Type() == SCH_FIELD_T && !( (SCH_FIELD*) item )->IsVisible() ) + item->SetForceVisible( true ); + } + + if( sheet->PathHumanReadable() != m_CurrentSheet->PathHumanReadable() ) + { + sheet->LastScreen()->SetZoom( GetScreen()->GetZoom() ); + *m_CurrentSheet = *sheet; + m_CurrentSheet->UpdateAllScreenReferences(); + SetScreen( sheet->LastScreen() ); + } + + // careful here + SetCrossHairPosition( data.GetPosition() ); + + RedrawScreen( data.GetPosition(), warpCursor ); + + msg = m_foundItems.GetText(); + + if( aEvent.GetFlags() & FR_SEARCH_REPLACE ) + aEvent.SetFlags( aEvent.GetFlags() | FR_REPLACE_ITEM_FOUND ); + } + else + { + if( aEvent.GetFlags() & FR_SEARCH_REPLACE ) + aEvent.SetFlags( aEvent.GetFlags() & ~FR_REPLACE_ITEM_FOUND ); + + msg.Printf( _( "No item found matching %s." ), GetChars( aEvent.GetFindString() ) ); + } + + SetStatusText( msg ); +} diff --git a/eeschema/general.h b/eeschema/general.h new file mode 100644 index 00000000..7f8b1474 --- /dev/null +++ b/eeschema/general.h @@ -0,0 +1,150 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 + */ + +/** + * @file general.h + */ + +#ifndef _GENERAL_H_ +#define _GENERAL_H_ + +#include // for EDA_COLOR_T + +class TRANSFORM; +class SCH_SHEET; + +#define EESCHEMA_VERSION 2 +#define SCHEMATIC_HEAD_STRING "Schematic File Version" + +#define TXTMARGE 10 // Offset in mils for placement of labels and pin numbers +#define DANGLING_SYMBOL_SIZE 12 + + +#define DEFAULT_REPEAT_OFFSET_X 0 ///< the default X value (overwritten by the eeschema config) +#define DEFAULT_REPEAT_OFFSET_Y 100 ///< the default Y value (overwritten by the eeschema config) +#define REPEAT_OFFSET_MAX 1000 ///< the max value of repeat offset value +#define DEFAULT_REPEAT_LABEL_INC 1 ///< the default value (overwritten by the eeschema config) +#define DEFAULT_REPEAT_OFFSET_PIN 100 ///< the default value (overwritten by the eeschema config) + ///< when repeating a pin + +///< The thickness to draw busses that do not have a specific width +///< (can be changed in preference menu) +#define DEFAULTBUSTHICKNESS 12 + +///< The thickness to draw lines that thickness is set to 0 (default thickness) +///< (can be changed in preference menu) +#define DEFAULTDRAWLINETHICKNESS 6 + +///< The default pin len value when creating pins(can be changed in preference menu) +#define DEFAULTPINLENGTH 200 + +///< The default pin len value when creating pins(can be changed in preference menu) +#define DEFAULTPINNUMSIZE 50 + +///< The default pin len value when creating pins(can be changed in preference menu) +#define DEFAULTPINNAMESIZE 50 + +#define GR_DEFAULT_DRAWMODE GR_COPY + +// this enum is for color management +// Using here "LAYER" in name is due to historical reasons. +// Eeschema does not actually use layers. It just uses "LAYER_XX" as identifier +// mainly for item color +typedef enum { + LAYER_FIRST, + LAYER_WIRE = LAYER_FIRST, + LAYER_BUS, + LAYER_JUNCTION, + LAYER_LOCLABEL, + LAYER_GLOBLABEL, + LAYER_HIERLABEL, + LAYER_PINNUM, + LAYER_PINNAM, + LAYER_REFERENCEPART, + LAYER_VALUEPART, + LAYER_FIELDS, + LAYER_DEVICE, + LAYER_NOTES, + LAYER_NETNAM, + LAYER_PIN, + LAYER_SHEET, + LAYER_SHEETNAME, + LAYER_SHEETFILENAME, + LAYER_SHEETLABEL, + LAYER_NOCONNECT, + LAYER_ERC_WARN, + LAYER_ERC_ERR, + LAYER_DEVICE_BACKGROUND, + LAYER_GRID, + LAYER_BACKGROUND, + LAYERSCH_ID_COUNT +} LAYERSCH_ID; + +inline LAYERSCH_ID operator++( LAYERSCH_ID& a ) +{ + a = LAYERSCH_ID( int( a ) + 1 ); + return a; +} + + +/* Rotation, mirror of graphic items in components bodies are handled by a + * transform matrix. The default matrix is useful to draw lib entries with + * using this default matrix ( no rotation, no mirror but Y axis is bottom to top, and + * Y draw axis is to to bottom so we must have a default matrix that reverses + * the Y coordinate and keeps the X coordiate + */ +extern TRANSFORM DefaultTransform; + +/* First and main (root) screen */ +extern SCH_SHEET* g_RootSheet; + +/** + * Default line thickness used to draw/plot items having a + * default thickness line value (i.e. = 0 ). + */ +int GetDefaultLineThickness(); +void SetDefaultLineThickness( int aThickness ); + +/** + * Default size for text in general + */ +int GetDefaultTextSize(); +void SetDefaultTextSize( int aSize ); + +/** + * Default line thickness used to draw/plot busses. + */ +int GetDefaultBusThickness(); +void SetDefaultBusThickness( int aThickness ); + +EDA_COLOR_T GetLayerColor( LAYERSCH_ID aLayer ); +void SetLayerColor( EDA_COLOR_T aColor, LAYERSCH_ID aLayer ); + +// Color to draw selected items +EDA_COLOR_T GetItemSelectedColor(); + +// Color to draw items flagged invisible, in libedit (they are invisible in Eeschema +EDA_COLOR_T GetInvisibleItemColor(); + +#endif // _GENERAL_H_ diff --git a/eeschema/getpart.cpp b/eeschema/getpart.cpp new file mode 100644 index 00000000..8c8db7ea --- /dev/null +++ b/eeschema/getpart.cpp @@ -0,0 +1,402 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2012 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file getpart.cpp + * @brief functions to get and place library components. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFilter, + LIB_ALIAS* aPreselectedAlias, + int* aUnit, int* aConvert ) +{ + // Close any open non-modal Lib browser, and open a new one, in "modal" mode: + LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false ); + + if( viewlibFrame ) + viewlibFrame->Destroy(); + + viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, true ); + + if( aFilter ) + viewlibFrame->SetFilter( aFilter ); + + if( aPreselectedAlias ) + { + viewlibFrame->SetSelectedLibrary( aPreselectedAlias->GetLibraryName() ); + viewlibFrame->SetSelectedComponent( aPreselectedAlias->GetName() ); + } + + if( aUnit && *aUnit > 0 ) + viewlibFrame->SetUnit( *aUnit ); + + if( aConvert && *aConvert > 0 ) + viewlibFrame->SetConvert( *aConvert ); + + viewlibFrame->Refresh(); + + wxString cmpname; + + if( viewlibFrame->ShowModal( &cmpname, this ) ) + { + if( aUnit ) + *aUnit = viewlibFrame->GetUnit(); + + if( aConvert ) + *aConvert = viewlibFrame->GetConvert(); + } + + viewlibFrame->Destroy(); + + return cmpname; +} + + +wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const SCHLIB_FILTER* aFilter, + wxArrayString& aHistoryList, + int& aHistoryLastUnit, + bool aUseLibBrowser, + int* aUnit, + int* aConvert ) +{ + wxString dialogTitle; + PART_LIBS* libs = Prj().SchLibs(); + + COMPONENT_TREE_SEARCH_CONTAINER search_container( libs ); // Container doing search-as-you-type + bool loaded = false; + + if( aFilter ) + { + const wxArrayString& liblist = aFilter->GetAllowedLibList(); + + for( unsigned ii = 0; ii < liblist.GetCount(); ii++ ) + { + PART_LIB* currLibrary = libs->FindLibrary( liblist[ii] ); + + if( currLibrary ) + { + loaded = true; + search_container.AddLibrary( *currLibrary ); + } + } + + if( aFilter->GetFilterPowerParts() ) + search_container.SetFilter( COMPONENT_TREE_SEARCH_CONTAINER::CMP_FILTER_POWER ); + + } + + if( !loaded ) + { + BOOST_FOREACH( PART_LIB& lib, *libs ) + { + search_container.AddLibrary( lib ); + } + } + + + if( !aHistoryList.empty() ) + { + // This is good for a transition for experienced users: giving them a History. Ideally, + // we actually make this part even faster to access with a popup on ALT-a or something. + // the history is under a node named "-- History --" + // However, because it is translatable, and we need to have a node name starting by "-- " + // because we (later) sort all node names alphabetically and this node should be the first, + // we build it with only with "History" string translatable + wxString nodename; + nodename << wxT("-- ") << _("History") << wxT(" --"); + search_container.AddAliasList( nodename, aHistoryList, NULL ); + search_container.SetPreselectNode( aHistoryList[0], aHistoryLastUnit ); + } + + const int deMorgan = aConvert ? *aConvert : 1; + dialogTitle.Printf( _( "Choose Component (%d items loaded)" ), search_container.GetComponentsCount() ); + DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, &search_container, deMorgan ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return wxEmptyString; + + wxString cmpName; + LIB_ALIAS* const alias = dlg.GetSelectedAlias( aUnit ); + if ( alias ) + cmpName = alias->GetName(); + + if( dlg.IsExternalBrowserSelected() ) // User requested component browser. + cmpName = SelectComponentFromLibBrowser( aFilter, alias, aUnit, aConvert); + + if( !cmpName.empty() ) + { + AddHistoryComponentName( aHistoryList, cmpName ); + if ( aUnit ) aHistoryLastUnit = *aUnit; + } + + return cmpName; +} + + +SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC, + const SCHLIB_FILTER* aFilter, + wxArrayString& aHistoryList, + int& aHistoryLastUnit, + bool aUseLibBrowser ) +{ + int unit = 1; + int convert = 1; + SetRepeatItem( NULL ); + m_canvas->SetIgnoreMouseEvents( true ); + + wxString name = SelectComponentFromLibrary( aFilter, aHistoryList, aHistoryLastUnit, + aUseLibBrowser, &unit, &convert ); + + if( name.IsEmpty() ) + { + m_canvas->SetIgnoreMouseEvents( false ); + m_canvas->MoveCursorToCrossHair(); + return NULL; + } + + m_canvas->SetIgnoreMouseEvents( false ); + m_canvas->MoveCursorToCrossHair(); + + wxString libsource; // the library name to use. If empty, load from any lib + + if( aFilter ) + libsource = aFilter->GetLibSource(); + + LIB_PART* part = Prj().SchLibs()->FindLibPart( name, libsource ); + + if( !part ) + { + wxString msg = wxString::Format( _( + "Failed to find part '%s' in library" ), + GetChars( name ) + ); + wxMessageBox( msg ); + return NULL; + } + + SCH_COMPONENT* component = new SCH_COMPONENT( *part, m_CurrentSheet, unit, convert, + GetCrossHairPosition(), true ); + + // Set the m_ChipName value, from component name in lib, for aliases + // Note if part is found, and if name is an alias of a component, + // alias exists because its root component was found + component->SetPartName( name ); + + // Be sure the link to the corresponding LIB_PART is OK: + component->Resolve( Prj().SchLibs() ); + + // Set the component value that can differ from component name in lib, for aliases + component->GetField( VALUE )->SetText( name ); + + MSG_PANEL_ITEMS items; + + component->SetCurrentSheetPath( &GetCurrentSheet() ); + component->GetMsgPanelInfo( items ); + + SetMsgPanel( items ); + component->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + component->SetFlags( IS_NEW ); + PrepareMoveItem( (SCH_ITEM*) component, aDC ); + + return component; +} + + +void SCH_EDIT_FRAME::OrientComponent( COMPONENT_ORIENTATION_T aOrientation ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T, + wxT( "Cannot change orientation of invalid schematic item." ) ); + + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + m_canvas->MoveCursorToCrossHair(); + + if( component->GetFlags() == 0 ) + { + SaveCopyInUndoList( item, UR_CHANGED ); + GetScreen()->SetCurItem( NULL ); + } + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + // Erase the previous component in it's current orientation. + + m_canvas->CrossHairOff( &dc ); + + if( component->GetFlags() ) + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + else + { + component->SetFlags( IS_MOVED ); // do not redraw the component + m_canvas->RefreshDrawingRect( component->GetBoundingBox() ); + component->ClearFlags( IS_MOVED ); + } + + component->SetOrientation( aOrientation ); + + /* Redraw the component in the new position. */ + if( component->GetFlags() ) + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + else + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + + m_canvas->CrossHairOn( &dc ); + GetScreen()->TestDanglingEnds( m_canvas, &dc ); + OnModify(); +} + + +/* + * Handle select part in multi-unit part. + */ +void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T, + wxT( "Cannot select unit of invalid schematic item." ) ); + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + m_canvas->MoveCursorToCrossHair(); + + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1; + + if( LIB_PART* part = Prj().SchLibs()->FindLibPart( component->GetPartName() ) ) + { + int unitCount = part->GetUnitCount(); + + wxCHECK_RET( (unit >= 1) && (unit <= unitCount), + wxString::Format( wxT( "Cannot select unit %d from component " ), unit ) + + part->GetName() ); + + if( unitCount <= 1 || component->GetUnit() == unit ) + return; + + if( unit > unitCount ) + unit = unitCount; + + STATUS_FLAGS flags = component->GetFlags(); + + if( !flags ) // No command in progress: save in undo list + SaveCopyInUndoList( component, UR_CHANGED ); + + if( flags ) + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode, g_GhostColor ); + else + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode ); + + /* Update the unit number. */ + component->SetUnitSelection( m_CurrentSheet, unit ); + component->SetUnit( unit ); + component->ClearFlags(); + component->SetFlags( flags ); // Restore m_Flag modified by SetUnit() + + /* Redraw the component in the new position. */ + if( flags ) + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode, g_GhostColor ); + else + component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + + screen->TestDanglingEnds( m_canvas, &dc ); + OnModify(); + } +} + + +void SCH_EDIT_FRAME::ConvertPart( SCH_COMPONENT* DrawComponent, wxDC* DC ) +{ + if( !DrawComponent ) + return; + + if( LIB_PART* part = Prj().SchLibs()->FindLibPart( DrawComponent->GetPartName() ) ) + { + if( !part->HasConversion() ) + { + DisplayError( this, wxT( "No convert found" ) ); + return; + } + + STATUS_FLAGS flags = DrawComponent->GetFlags(); + + if( DrawComponent->GetFlags() ) + DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode, g_GhostColor ); + else + DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode ); + + DrawComponent->SetConvert( DrawComponent->GetConvert() + 1 ); + + // ensure m_Convert = 0, 1 or 2 + // 0 and 1 = shape 1 = not converted + // 2 = shape 2 = first converted shape + // > 2 is not used but could be used for more shapes + // like multiple shapes for a programmable component + // When m_Convert = val max, return to the first shape + if( DrawComponent->GetConvert() > 2 ) + DrawComponent->SetConvert( 1 ); + + DrawComponent->ClearFlags(); + DrawComponent->SetFlags( flags ); // Restore m_Flag (modified by SetConvert()) + + /* Redraw the component in the new position. */ + if( DrawComponent->IsMoving() ) + DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode, g_GhostColor ); + else + DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + + GetScreen()->TestDanglingEnds( m_canvas, DC ); + OnModify(); + } +} diff --git a/eeschema/help_common_strings.h b/eeschema/help_common_strings.h new file mode 100644 index 00000000..f1f8515b --- /dev/null +++ b/eeschema/help_common_strings.h @@ -0,0 +1,90 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 CERN + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 + */ + +/** + * @file eeschema/help_common_strings.h + * strings common to toolbars and menubar + */ + +/** + * These strings are used in menus and tools, that do the same command + * But they are internationalized, and therefore must be created + * at run time, on the fly. + * So they cannot be static. + * + * Therefore they are defined by \#define, used inside menu constructors + */ + +// Common to schematic editor and component editor +#define HELP_UNDO _( "Undo last command" ) +#define HELP_REDO _( "Redo last command" ) + +#define HELP_ZOOM_IN _( "Zoom in" ) +#define HELP_ZOOM_OUT _( "Zoom out" ) +#define HELP_ZOOM_FIT _( "Fit schematic sheet on screen" ) +#define HELP_ZOOM_REDRAW _( "Redraw schematic view" ) + +#define HELP_DELETE_ITEMS _( "Delete item" ) + +// Schematic editor: +#define HELP_FIND _( "Find components and text" ) +#define HELP_REPLACE _( "Find and replace text in schematic items" ) +#define HELP_PLACE_COMPONENTS _( "Place component" ) +#define HELP_PLACE_POWERPORT _( "Place power port" ) +#define HELP_PLACE_WIRE _( "Place wire" ) +#define HELP_PLACE_BUS _( "Place bus" ) +#define HELP_PLACE_WIRE2BUS_ENTRY _( "Place wire to bus entry" ) +#define HELP_PLACE_BUS2BUS_ENTRY _( "Place bus to bus entry" ) +#define HELP_PLACE_NC_FLAG _( "Place not-connected flag" ) + +#define HELP_PLACE_NETLABEL _( "Place net name - local label" ) +#define HELP_PLACE_GLOBALLABEL \ + _(\ + "Place global label.\nWarning: inside global hierarchy , all global labels with same name are connected" ) +#define HELP_PLACE_HIER_LABEL \ + _( "Place a hierarchical label. Label will be seen as a hierarchical pin in the sheet symbol" ) + +#define HELP_PLACE_JUNCTION _( "Place junction" ) +#define HELP_PLACE_SHEET _( "Create hierarchical sheet" ) +#define HELP_IMPORT_SHEETPIN _( \ + "Place hierarchical pin imported from the corresponding hierarchical label" ) +#define HELP_PLACE_SHEETPIN _( "Place hierarchical pin in sheet" ) +#define HELP_PLACE_GRAPHICLINES _( "Place graphic lines or polygons" ) +#define HELP_PLACE_GRAPHICTEXTS _( "Place text" ) + +#define HELP_ANNOTATE _( "Annotate schematic components" ) +#define HELP_RUN_LIB_EDITOR _( "Library Editor - Create/edit components" ) +#define HELP_RUN_LIB_VIEWER _( "Library Browser - Browse components" ) +#define HELP_GENERATE_BOM _( "Generate bill of materials and/or cross references" ) +#define HELP_IMPORT_FOOTPRINTS \ + _( "Back-import component footprint fields via CvPcb .cmp file" ) + +// Component editor: +#define HELP_ADD_PIN _( "Add pins to component" ) +#define HELP_ADD_BODYTEXT _( "Add text to component body" ) +#define HELP_ADD_BODYRECT _( "Add graphic rectangle to component body" ) +#define HELP_ADD_BODYCIRCLE _( "Add circles to component body" ) +#define HELP_ADD_BODYARC _( "Add arcs to component body" ) +#define HELP_ADD_BODYPOLYGON _( "Add lines and polygons to component body" ) +#define HELP_PLACE_GRAPHICIMAGES _("Add bitmap image") diff --git a/eeschema/hierarch.cpp b/eeschema/hierarch.cpp new file mode 100644 index 00000000..578274b1 --- /dev/null +++ b/eeschema/hierarch.cpp @@ -0,0 +1,313 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file hierarch.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +enum +{ + ID_TREECTRL_HIERARCHY = 1600 +}; + + +class HIERARCHY_NAVIG_DLG; + +/* This class derived from wxTreeItemData stores the SCH_SHEET_PATH of each + * sheet in hierarchy in each TreeItem, in its associated data buffer +*/ +class TreeItemData : public wxTreeItemData +{ +public: + SCH_SHEET_PATH m_SheetPath; + + TreeItemData( SCH_SHEET_PATH& sheet ) : wxTreeItemData() + { + m_SheetPath = sheet; + } +}; + +/* Class to handle hierarchy tree. */ +class HIERARCHY_TREE : public wxTreeCtrl +{ +private: + HIERARCHY_NAVIG_DLG* m_Parent; + wxImageList* imageList; + +public: + HIERARCHY_TREE() + { + m_Parent = NULL; + imageList = NULL; + } + + HIERARCHY_TREE( HIERARCHY_NAVIG_DLG* parent ); + + DECLARE_DYNAMIC_CLASS( HIERARCHY_TREE ) +}; + +IMPLEMENT_DYNAMIC_CLASS( HIERARCHY_TREE, wxTreeCtrl ) + + +HIERARCHY_TREE::HIERARCHY_TREE( HIERARCHY_NAVIG_DLG* parent ) : + wxTreeCtrl( (wxWindow*)parent, ID_TREECTRL_HIERARCHY, wxDefaultPosition, wxDefaultSize, + wxTR_HAS_BUTTONS, wxDefaultValidator, wxT( "HierachyTreeCtrl" ) ) +{ + m_Parent = parent; + + // Make an image list containing small icons + // All icons are expected having the same size. + wxBitmap tree_nosel_bm( KiBitmap( tree_nosel_xpm ) ); + imageList = new wxImageList( tree_nosel_bm.GetWidth(), + tree_nosel_bm.GetHeight(), true, 2 ); + + imageList->Add( tree_nosel_bm ); + imageList->Add( KiBitmap( tree_sel_xpm ) ); + + AssignImageList( imageList ); +} + + +class HIERARCHY_NAVIG_DLG : public wxDialog +{ +public: + SCH_EDIT_FRAME* m_Parent; + HIERARCHY_TREE* m_Tree; + int m_nbsheets; + +private: + wxSize m_TreeSize; + int maxposx; + +public: + HIERARCHY_NAVIG_DLG( SCH_EDIT_FRAME* aParent, const wxPoint& aPos ); + void BuildSheetsTree( SCH_SHEET_PATH* list, wxTreeItemId* previousmenu ); + + ~HIERARCHY_NAVIG_DLG(); + + void OnSelect( wxTreeEvent& event ); + +private: + void OnQuit( wxCommandEvent& event ); + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE( HIERARCHY_NAVIG_DLG, wxDialog ) + EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL_HIERARCHY, HIERARCHY_NAVIG_DLG::OnSelect ) +END_EVENT_TABLE() + + +void SCH_EDIT_FRAME::InstallHierarchyFrame( wxPoint& pos ) +{ + HIERARCHY_NAVIG_DLG* treeframe = new HIERARCHY_NAVIG_DLG( this, pos ); + + treeframe->ShowModal(); + treeframe->Destroy(); +} + + +HIERARCHY_NAVIG_DLG::HIERARCHY_NAVIG_DLG( SCH_EDIT_FRAME* aParent, const wxPoint& aPos ) : + wxDialog( aParent, wxID_ANY, _( "Navigator" ), aPos, wxSize( 110, 50 ), + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ) +{ + wxTreeItemId cellule; + + m_Parent = aParent; + m_Tree = new HIERARCHY_TREE( this ); + + m_nbsheets = 1; + + cellule = m_Tree->AddRoot( _( "Root" ), 0, 1 ); + m_Tree->SetItemBold( cellule, true ); + + SCH_SHEET_PATH list; + list.Push( g_RootSheet ); + m_Tree->SetItemData( cellule, new TreeItemData( list ) ); + + if( m_Parent->GetCurrentSheet().Last() == g_RootSheet ) + m_Tree->SelectItem( cellule ); //root. + + maxposx = 15; + BuildSheetsTree( &list, &cellule ); + + m_Tree->Expand( cellule ); + + wxRect itemrect; + m_Tree->GetBoundingRect( cellule, itemrect ); + + // Set dialog window size to be large enough + m_TreeSize.x = itemrect.GetWidth() + 20; + m_TreeSize.x = std::max( m_TreeSize.x, 250 ); + + // Readjust the size of the frame to an optimal value. + m_TreeSize.y = m_nbsheets * itemrect.GetHeight(); + m_TreeSize.y += 10; + + SetClientSize( m_TreeSize ); +} + + +HIERARCHY_NAVIG_DLG::~HIERARCHY_NAVIG_DLG() +{ +} + + +void HIERARCHY_NAVIG_DLG::OnQuit( wxCommandEvent& event ) +{ + // true is to force the frame to close + Close( true ); +} + + +/* Routine to create the hierarchical tree of the schematic + * This routine is re-entrant! + */ +void HIERARCHY_NAVIG_DLG::BuildSheetsTree( SCH_SHEET_PATH* list, wxTreeItemId* previousmenu ) + +{ + wxTreeItemId menu; + + if( m_nbsheets > NB_MAX_SHEET ) + { + if( m_nbsheets == (NB_MAX_SHEET + 1) ) + { + wxString msg; + msg << wxT( "BuildSheetsTree: Error: nbsheets > " ) << NB_MAX_SHEET; + DisplayError( this, msg ); + m_nbsheets++; + } + + return; + } + + maxposx += m_Tree->GetIndent(); + SCH_ITEM* schitem = list->LastDrawList(); + + while( schitem && m_nbsheets < NB_MAX_SHEET ) + { + if( schitem->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) schitem; + m_nbsheets++; + menu = m_Tree->AppendItem( *previousmenu, sheet->GetName(), 0, 1 ); + list->Push( sheet ); + m_Tree->SetItemData( menu, new TreeItemData( *list ) ); + int ll = m_Tree->GetItemText( menu ).Len(); + +#ifdef __WINDOWS__ + ll *= 9; // * char width +#else + ll *= 12; // * char width +#endif + ll += maxposx + 20; + m_TreeSize.x = std::max( m_TreeSize.x, ll ); + m_TreeSize.y += 1; + + if( *list == m_Parent->GetCurrentSheet() ) + { + m_Tree->EnsureVisible( menu ); + m_Tree->SelectItem( menu ); + } + + BuildSheetsTree( list, &menu ); + m_Tree->Expand( menu ); + list->Pop(); + } + + schitem = schitem->Next(); + } + + maxposx -= m_Tree->GetIndent(); +} + + +/* Called on a double-click on a tree item: + * Open the selected sheet, and display the corresponding screen + */ +void HIERARCHY_NAVIG_DLG::OnSelect( wxTreeEvent& event ) + +{ + wxTreeItemId ItemSel = m_Tree->GetSelection(); + + m_Parent->SetCurrentSheet(( (TreeItemData*) m_Tree->GetItemData( ItemSel ) )->m_SheetPath ); + m_Parent->DisplayCurrentSheet(); + Close( true ); +} + + +void SCH_EDIT_FRAME::DisplayCurrentSheet() +{ + SetRepeatItem( NULL ); + ClearMsgPanel(); + + SCH_SCREEN* screen = m_CurrentSheet->LastScreen(); + + // Switch to current sheet, + // and update the grid size, because it can be modified in latest screen + SetScreen( screen ); + GetScreen()->SetGrid( m_LastGridSizeId + ID_POPUP_GRID_LEVEL_1000 ); + + // update the References + m_CurrentSheet->UpdateAllScreenReferences(); + SetSheetNumberAndCount(); + m_canvas->SetCanStartBlock( -1 ); + + if( screen->m_FirstRedraw ) + { + Zoom_Automatique( false ); + screen->m_FirstRedraw = false; + SetCrossHairPosition( GetScrollCenterPosition() ); + m_canvas->MoveCursorToCrossHair(); + screen->SchematicCleanUp( GetCanvas(), NULL ); + } + else + { + RedrawScreen( GetScrollCenterPosition(), true ); + } + + // Now refresh m_canvas. Should be not necessary, but because screen has changed + // the previous refresh has set all new draw parameters (scroll position ..) + // but most of time there were some inconsitencies about cursor parameters + // ( previous position of cursor ...) and artefacts can happen + // mainly when sheet size has changed + // This second refresh clears artefacts because at this point, + // all parameters are now updated + m_canvas->Refresh(); +} diff --git a/eeschema/hotkeys.cpp b/eeschema/hotkeys.cpp new file mode 100644 index 00000000..743371ab --- /dev/null +++ b/eeschema/hotkeys.cpp @@ -0,0 +1,876 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2017 Wayne Stambaugh + * Copyright (C) 2004-2017 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 + */ + +/** + * @file eeschema/hotkeys.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Remark: the hotkey message info is used as keyword in hotkey config files and +// as comments in help windows, therefore translated only when displayed +// they are marked _HKI to be extracted by translation tools +// See hotkeys_basic.h for more info + + +/* How to add a new hotkey: + * add a new id in the enum hotkey_id_command like MY_NEW_ID_FUNCTION (see + * hotkeys.h). + * add a new EDA_HOTKEY entry like: + * static EDA_HOTKEY HkMyNewEntry(_HKI("Command Label"), MY_NEW_ID_FUNCTION, + * default key value); + * _HKI("Command Label") is the name used in hotkey list display, and the + * identifier in the hotkey list file + * MY_NEW_ID_FUNCTION is an equivalent id function used in the switch in + * OnHotKey() function. + * default key value is the default hotkey for this command. Can be overridden + * by the user hotkey list file + * add the HkMyNewEntry pointer in the schematic_Hotkey_List list or the + * libEdit_Hotkey_List list or common_Hotkey_List if the same command is + * added both in Eeschema and libedit) + * Add the new code in the switch in OnHotKey() function. + * when the variable itemInEdit is true, an item is currently edited. + * This can be useful if the new function cannot be executed while an item is + * currently being edited + * ( For example, one cannot start a new wire when a component is moving.) + * + * Note: If an hotkey is a special key be sure the corresponding wxWidget + * keycode (WXK_XXXX) is handled in the hotkey_name_descr + * s_Hotkey_Name_List list (see hotkeys_basic.cpp) and see this list + * for some ascii keys (space ...) + * + * Key modifier are: GR_KB_CTRL GR_KB_ALT + */ + + +// Common commands + +// Fit on Screen +#if !defined( __WXMAC__ ) +static EDA_HOTKEY HkZoomAuto( _HKI( "Fit on Screen" ), HK_ZOOM_AUTO, WXK_HOME, ID_ZOOM_PAGE ); +#else +static EDA_HOTKEY HkZoomAuto( _HKI( "Zoom Auto" ), HK_ZOOM_AUTO, GR_KB_CTRL + '0', + ID_ZOOM_PAGE ); +#endif + +static EDA_HOTKEY HkZoomCenter( _HKI( "Zoom Center" ), HK_ZOOM_CENTER, WXK_F4, + ID_POPUP_ZOOM_CENTER ); + +// Refresh Screen +#if !defined( __WXMAC__ ) +static EDA_HOTKEY HkZoomRedraw( _HKI( "Zoom Redraw" ), HK_ZOOM_REDRAW, WXK_F3, ID_ZOOM_REDRAW ); +#else +static EDA_HOTKEY HkZoomRedraw( _HKI( "Zoom Redraw" ), HK_ZOOM_REDRAW, GR_KB_CTRL + 'R', + ID_ZOOM_REDRAW ); +#endif + +// Zoom In +#if !defined( __WXMAC__ ) +static EDA_HOTKEY HkZoomIn( _HKI( "Zoom In" ), HK_ZOOM_IN, WXK_F1, ID_POPUP_ZOOM_IN ); +#else +static EDA_HOTKEY HkZoomIn( _HKI( "Zoom In" ), HK_ZOOM_IN, GR_KB_CTRL + '+', ID_POPUP_ZOOM_IN ); +#endif + +// Zoom Out +#if !defined( __WXMAC__ ) +static EDA_HOTKEY HkZoomOut( _HKI( "Zoom Out" ), HK_ZOOM_OUT, WXK_F2, ID_POPUP_ZOOM_OUT ); +#else +static EDA_HOTKEY HkZoomOut( _HKI( "Zoom Out" ), HK_ZOOM_OUT, GR_KB_CTRL + '-', ID_POPUP_ZOOM_OUT ); +#endif + +static EDA_HOTKEY HkHelp( _HKI( "Help (this window)" ), HK_HELP, '?' ); +static EDA_HOTKEY HkResetLocalCoord( _HKI( "Reset Local Coordinates" ), HK_RESET_LOCAL_COORD, ' ' ); +static EDA_HOTKEY HkLeaveSheet( _HKI( "Leave Sheet" ), HK_LEAVE_SHEET, GR_KB_ALT + WXK_BACK, + ID_POPUP_SCH_LEAVE_SHEET ); + +// Undo +static EDA_HOTKEY HkUndo( _HKI( "Undo" ), HK_UNDO, GR_KB_CTRL + 'Z', (int) wxID_UNDO ); + +// Redo +#if !defined( __WXMAC__ ) +static EDA_HOTKEY HkRedo( _HKI( "Redo" ), HK_REDO, GR_KB_CTRL + 'Y', (int) wxID_REDO ); +#else +static EDA_HOTKEY HkRedo( _HKI( "Redo" ), HK_REDO, GR_KB_SHIFT + GR_KB_CTRL + 'Z', + (int) wxID_REDO ); +#endif + +// mouse click command: +static EDA_HOTKEY HkMouseLeftClick( _HKI( "Mouse Left Click" ), HK_LEFT_CLICK, WXK_RETURN, 0 ); +static EDA_HOTKEY HkMouseLeftDClick( _HKI( "Mouse Left Double Click" ), HK_LEFT_DCLICK, WXK_END, 0 ); + +// Schematic editor +static EDA_HOTKEY HkBeginWire( _HKI( "Begin Wire" ), HK_BEGIN_WIRE, 'W', ID_WIRE_BUTT ); +static EDA_HOTKEY HkBeginBus( _HKI( "Begin Bus" ), HK_BEGIN_BUS, 'B', ID_BUS_BUTT ); +static EDA_HOTKEY HkEndLineWireBus( _HKI( "End Line Wire Bus" ), HK_END_CURR_LINEWIREBUS, 'K', + ID_POPUP_END_LINE ); + +static EDA_HOTKEY HkAddLabel( _HKI( "Add Label" ), HK_ADD_LABEL, 'L', ID_LABEL_BUTT ); +static EDA_HOTKEY HkAddHierarchicalLabel( _HKI( "Add Hierarchical Label" ), HK_ADD_HLABEL, 'H', + ID_HIERLABEL_BUTT ); +static EDA_HOTKEY HkAddGlobalLabel( _HKI( "Add Global Label" ), HK_ADD_GLABEL, GR_KB_CTRL + 'H', + ID_GLABEL_BUTT ); +static EDA_HOTKEY HkAddJunction( _HKI( "Add Junction" ), HK_ADD_JUNCTION, 'J', ID_JUNCTION_BUTT ); +static EDA_HOTKEY HkAddComponent( _HKI( "Add Component" ), HK_ADD_NEW_COMPONENT, 'A', + ID_SCH_PLACE_COMPONENT ); +static EDA_HOTKEY HkAddPower( _HKI( "Add Power" ), HK_ADD_NEW_POWER, 'P', + ID_PLACE_POWER_BUTT ); +static EDA_HOTKEY HkAddNoConn( _HKI( "Add No Connect Flag" ), HK_ADD_NOCONN_FLAG, 'Q', + ID_NOCONN_BUTT ); +static EDA_HOTKEY HkAddHierSheet( _HKI( "Add Sheet" ), HK_ADD_HIER_SHEET, 'S', + ID_SHEET_SYMBOL_BUTT ); +static EDA_HOTKEY HkAddBusEntry( _HKI( "Add Bus Entry" ), HK_ADD_BUS_ENTRY, '/', + ID_BUSTOBUS_ENTRY_BUTT ); +static EDA_HOTKEY HkAddWireEntry( _HKI( "Add Wire Entry" ), HK_ADD_WIRE_ENTRY, 'Z', + ID_WIRETOBUS_ENTRY_BUTT ); +static EDA_HOTKEY HkAddGraphicPolyLine( _HKI( "Add Graphic PolyLine" ), HK_ADD_GRAPHIC_POLYLINE, + 'I', ID_LINE_COMMENT_BUTT ); +static EDA_HOTKEY HkAddGraphicText( _HKI( "Add Graphic Text" ), HK_ADD_GRAPHIC_TEXT, 'T', + ID_TEXT_COMMENT_BUTT ); +static EDA_HOTKEY HkMirrorY( _HKI( "Mirror Y" ), HK_MIRROR_Y, 'Y', + ID_SCH_MIRROR_Y ); +static EDA_HOTKEY HkMirrorX( _HKI( "Mirror X" ), HK_MIRROR_X, 'X', + ID_SCH_MIRROR_X ); +static EDA_HOTKEY HkOrientNormalComponent( _HKI( "Orient Normal Component" ), + HK_ORIENT_NORMAL_COMPONENT, 'N', ID_SCH_ORIENT_NORMAL ); +static EDA_HOTKEY HkRotate( _HKI( "Rotate Item" ), HK_ROTATE, 'R', ID_SCH_ROTATE_CLOCKWISE ); +static EDA_HOTKEY HkEdit( _HKI( "Edit Item" ), HK_EDIT, 'E', ID_SCH_EDIT_ITEM ); +static EDA_HOTKEY HkEditComponentValue( _HKI( "Edit Component Value" ), + HK_EDIT_COMPONENT_VALUE, 'V', + ID_SCH_EDIT_COMPONENT_VALUE ); +static EDA_HOTKEY HkEditComponentReference( _HKI( "Edit Component Reference" ), + HK_EDIT_COMPONENT_REFERENCE, 'U', + ID_SCH_EDIT_COMPONENT_REFERENCE ); +static EDA_HOTKEY HkEditComponentFootprint( _HKI( "Edit Component Footprint" ), + HK_EDIT_COMPONENT_FOOTPRINT, 'F', + ID_SCH_EDIT_COMPONENT_FOOTPRINT ); +static EDA_HOTKEY HkEditComponentWithLibedit( _HKI( "Edit with Component Editor" ), + HK_EDIT_COMPONENT_WITH_LIBEDIT, + 'E' + GR_KB_CTRL, + ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP ); +static EDA_HOTKEY HkMove( _HKI( "Move Schematic Item" ), + HK_MOVE_COMPONENT_OR_ITEM, 'M', + ID_SCH_MOVE_ITEM ); + +static EDA_HOTKEY HkCopyComponentOrText( _HKI( "Copy Component or Label" ), + HK_COPY_COMPONENT_OR_LABEL, 'C', + ID_POPUP_SCH_COPY_ITEM ); + +static EDA_HOTKEY HkDrag( _HKI( "Drag Item" ), HK_DRAG, 'G', ID_SCH_DRAG_ITEM ); +static EDA_HOTKEY HkSaveBlock( _HKI( "Save Block" ), HK_SAVE_BLOCK, 'C' + GR_KB_CTRL, wxID_COPY ); +static EDA_HOTKEY HkMove2Drag( _HKI( "Move Block -> Drag Block" ), + HK_MOVEBLOCK_TO_DRAGBLOCK, '\t', ID_POPUP_DRAG_BLOCK ); +static EDA_HOTKEY HkInsert( _HKI( "Repeat Last Item" ), HK_REPEAT_LAST, WXK_INSERT ); +static EDA_HOTKEY HkDelete( _HKI( "Delete Item" ), HK_DELETE, WXK_DELETE ); +static EDA_HOTKEY HkDeleteNode( _HKI( "Delete Node" ), HK_DELETE_NODE, WXK_BACK, + ID_POPUP_SCH_DELETE_NODE ); + +static EDA_HOTKEY HkFindItem( _HKI( "Find Item" ), HK_FIND_ITEM, 'F' + GR_KB_CTRL, ID_FIND_ITEMS ); +static EDA_HOTKEY HkFindNextItem( _HKI( "Find Next Item" ), HK_FIND_NEXT_ITEM, WXK_F5, + wxEVT_COMMAND_FIND ); +static EDA_HOTKEY HkFindReplace( _HKI( "Find and Replace" ), HK_FIND_REPLACE, + 'F' + GR_KB_CTRL + GR_KB_ALT, wxID_REPLACE ); +static EDA_HOTKEY HkFindNextDrcMarker( _HKI( "Find Next DRC Marker" ), HK_FIND_NEXT_DRC_MARKER, + WXK_F5 + GR_KB_SHIFT, EVT_COMMAND_FIND_DRC_MARKER ); + +// Special keys for library editor: +static EDA_HOTKEY HkCreatePin( _HKI( "Create Pin" ), HK_LIBEDIT_CREATE_PIN, 'P' ); +static EDA_HOTKEY HkInsertPin( _HKI( "Repeat Pin" ), HK_REPEAT_LAST, WXK_INSERT ); +static EDA_HOTKEY HkMoveLibItem( _HKI( "Move Library Item" ), HK_LIBEDIT_MOVE_GRAPHIC_ITEM, 'M' ); + +// Load/save files +static EDA_HOTKEY HkSaveLib( _HKI( "Save Library" ), HK_SAVE_LIB, 'S' + GR_KB_CTRL ); +static EDA_HOTKEY HkSaveSchematic( _HKI( "Save Schematic" ), HK_SAVE_SCH, 'S' + GR_KB_CTRL ); +static EDA_HOTKEY HkLoadSchematic( _HKI( "Load Schematic" ), HK_LOAD_SCH, 'L' + GR_KB_CTRL ); + +// List of common hotkey descriptors +static EDA_HOTKEY* common_Hotkey_List[] = +{ + &HkHelp, + &HkZoomIn, + &HkZoomOut, + &HkZoomRedraw, + &HkZoomCenter, + &HkZoomAuto, + &HkResetLocalCoord, + &HkEdit, + &HkDelete, + &HkRotate, + &HkDrag, + &HkUndo, + &HkRedo, + &HkMouseLeftClick, + &HkMouseLeftDClick, + NULL +}; + +// List of common hotkey descriptors, for the library vierwer +static EDA_HOTKEY* common_basic_Hotkey_List[] = +{ + &HkHelp, + &HkZoomIn, + &HkZoomOut, + &HkZoomRedraw, + &HkZoomCenter, + &HkZoomAuto, + &HkResetLocalCoord, + &HkMouseLeftClick, + &HkMouseLeftDClick, + NULL +}; + +// List of hotkey descriptors for schematic +static EDA_HOTKEY* schematic_Hotkey_List[] = +{ + &HkSaveSchematic, + &HkLoadSchematic, + &HkFindItem, + &HkFindNextItem, + &HkFindNextDrcMarker, + &HkFindReplace, + &HkInsert, + &HkMove2Drag, + &HkSaveBlock, + &HkMove, + &HkCopyComponentOrText, + &HkAddComponent, + &HkAddPower, + &HkMirrorX, + &HkMirrorY, + &HkOrientNormalComponent, + &HkEditComponentValue, + &HkEditComponentReference, + &HkEditComponentFootprint, + &HkEditComponentWithLibedit, + &HkBeginWire, + &HkBeginBus, + &HkEndLineWireBus, + &HkAddLabel, + &HkAddHierarchicalLabel, + &HkAddGlobalLabel, + &HkAddJunction, + &HkAddNoConn, + &HkAddHierSheet, + &HkAddWireEntry, + &HkAddBusEntry, + &HkAddGraphicPolyLine, + &HkAddGraphicText, + &HkLeaveSheet, + &HkDeleteNode, + NULL +}; + +// List of hotkey descriptors for library editor +static EDA_HOTKEY* libEdit_Hotkey_List[] = +{ + &HkSaveLib, + &HkCreatePin, + &HkInsertPin, + &HkMoveLibItem, + NULL +}; + +// List of hotkey descriptors for library viewer (currently empty +static EDA_HOTKEY* viewlib_Hotkey_List[] = +{ + NULL +}; + +// Keyword Identifiers (tags) in key code configuration file (section names) +// (.m_SectionTag member of a EDA_HOTKEY_CONFIG) +static wxString schematicSectionTag( wxT( "[eeschema]" ) ); +static wxString libEditSectionTag( wxT( "[libedit]" ) ); + +// Titles for hotkey editor and hotkey display +static wxString commonSectionTitle( _HKI( "Common" ) ); +static wxString schematicSectionTitle( _HKI( "Schematic Editor" ) ); +static wxString libEditSectionTitle( _HKI( "Library Editor" ) ); + +// list of sections and corresponding hotkey list for Eeschema (used to create +// an hotkey config file) +struct EDA_HOTKEY_CONFIG g_Eeschema_Hokeys_Descr[] = +{ + { &g_CommonSectionTag, common_Hotkey_List, &commonSectionTitle }, + { &schematicSectionTag, schematic_Hotkey_List, &schematicSectionTitle }, + { &libEditSectionTag, libEdit_Hotkey_List, &libEditSectionTitle }, + { NULL, NULL, NULL } +}; + +// list of sections and corresponding hotkey list for the schematic editor +// (used to list current hotkeys) +struct EDA_HOTKEY_CONFIG g_Schematic_Hokeys_Descr[] = +{ + { &g_CommonSectionTag, common_Hotkey_List, &commonSectionTitle }, + { &schematicSectionTag, schematic_Hotkey_List, &schematicSectionTitle }, + { NULL, NULL, NULL } +}; + +// list of sections and corresponding hotkey list for the component editor +// (used to list current hotkeys) +struct EDA_HOTKEY_CONFIG g_Libedit_Hokeys_Descr[] = +{ + { &g_CommonSectionTag, common_Hotkey_List, &commonSectionTitle }, + { &libEditSectionTag, libEdit_Hotkey_List, &libEditSectionTitle }, + { NULL, NULL, NULL } +}; + +// list of sections and corresponding hotkey list for the component browser +// (used to list current hotkeys) +struct EDA_HOTKEY_CONFIG g_Viewlib_Hokeys_Descr[] = +{ + { &g_CommonSectionTag, common_basic_Hotkey_List, &commonSectionTitle }, + { NULL, NULL, NULL } +}; + + +EDA_HOTKEY* SCH_EDIT_FRAME::GetHotKeyDescription( int aCommand ) const +{ + EDA_HOTKEY* HK_Descr = GetDescriptorFromCommand( aCommand, common_Hotkey_List ); + + if( HK_Descr == NULL ) + HK_Descr = GetDescriptorFromCommand( aCommand, schematic_Hotkey_List ); + + return HK_Descr; +} + + +/* + * Hot keys. Some commands are relative to the item under the mouse cursor + * Commands are case insensitive + */ +bool SCH_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem ) +{ + if( aHotKey == 0 ) + return false; + + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + + SCH_SCREEN* screen = GetScreen(); + + // itemInEdit == false means no item currently edited. We can ask for editing a new item + bool itemInEdit = screen->GetCurItem() && screen->GetCurItem()->GetFlags(); + + // blocInProgress == false means no block in progress. + // Because a drag command uses a drag block, false means also no drag in progress + // If false, we can ask for editing a new item + bool blocInProgress = screen->m_BlockLocate.GetState() != STATE_NO_BLOCK; + + // notBusy == true means no item currently edited and no other command in progress + // We can change active tool and ask for editing a new item + bool notBusy = (!itemInEdit) && (!blocInProgress); + + /* Convert lower to upper case (the usual toupper function has problem + * with non ascii codes like function keys */ + if( (aHotKey >= 'a') && (aHotKey <= 'z') ) + aHotKey += 'A' - 'a'; + + // Search command from key : + EDA_HOTKEY* hotKey = GetDescriptorFromHotkey( aHotKey, common_Hotkey_List ); + + if( hotKey == NULL ) + hotKey = GetDescriptorFromHotkey( aHotKey, schematic_Hotkey_List ); + + if( hotKey == NULL ) + return false; + + switch( hotKey->m_Idcommand ) + { + default: + case HK_NOT_FOUND: + return false; + + case HK_HELP: // Display Current hotkey list + DisplayHotkeyList( this, g_Schematic_Hokeys_Descr ); + break; + + case HK_RESET_LOCAL_COORD: // Reset the relative coord + GetScreen()->m_O_Curseur = GetCrossHairPosition(); + break; + + case HK_LEFT_CLICK: + case HK_LEFT_DCLICK: // Simulate a double left click: generate 2 events + if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE ) + { + GetCanvas()->SetAutoPanRequest( false ); + HandleBlockPlace( aDC ); + } + else if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK ) + { + OnLeftClick( aDC, aPosition ); + + if( hotKey->m_Idcommand == HK_LEFT_DCLICK ) + OnLeftDClick( aDC, aPosition ); + } + break; + + case HK_ZOOM_IN: + case HK_ZOOM_OUT: + case HK_ZOOM_REDRAW: + case HK_ZOOM_CENTER: + case HK_ZOOM_AUTO: +// case HK_ZOOM_SELECTION: + case HK_MOVEBLOCK_TO_DRAGBLOCK: // Switch to drag mode, when block moving + case HK_SAVE_BLOCK: // Copy block to paste buffer. + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_DELETE: + if( notBusy ) + DeleteItemAtCrossHair( aDC ); + break; + + case HK_REPEAT_LAST: + if( notBusy ) + RepeatDrawItem( aDC ); + break; + + case HK_END_CURR_LINEWIREBUS: + // this key terminates a new line/bus/wire in progress + if( aItem && aItem->IsNew() && + aItem->Type() == SCH_LINE_T ) + { + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + } + break; + + case HK_UNDO: // Hot keys that map to command IDs that cannot be called + case HK_REDO: // while busy performing another command. + case HK_FIND_ITEM: + case HK_FIND_REPLACE: + case HK_DELETE_NODE: + case HK_LEAVE_SHEET: + if( notBusy ) + { + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + } + break; + + case HK_FIND_NEXT_ITEM: + case HK_FIND_NEXT_DRC_MARKER: + if( notBusy ) + { + wxFindDialogEvent event( hotKey->m_IdMenuEvent, GetId() ); + event.SetEventObject( this ); + event.SetFlags( m_findReplaceData->GetFlags() ); + event.SetFindString( m_findReplaceData->GetFindString() ); + GetEventHandler()->ProcessEvent( event ); + } + break; + + case HK_ADD_NEW_COMPONENT: // Add component + case HK_ADD_NEW_POWER: // Add power component + case HK_ADD_LABEL: + case HK_ADD_HLABEL: + case HK_ADD_GLABEL: + case HK_ADD_JUNCTION: + case HK_ADD_WIRE_ENTRY: + case HK_ADD_BUS_ENTRY: + case HK_ADD_HIER_SHEET: + case HK_ADD_GRAPHIC_TEXT: + case HK_ADD_GRAPHIC_POLYLINE: + case HK_ADD_NOCONN_FLAG: // Add a no connected flag + case HK_BEGIN_BUS: + case HK_BEGIN_WIRE: + if( notBusy ) + { + EDA_HOTKEY_CLIENT_DATA data( aPosition ); + cmd.SetInt( aHotKey ); + cmd.SetClientObject( &data ); + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + } + else if( aItem && aItem->IsNew() ) + { + // If the item is a bus or a wire, a begin command is not possible. + if( (GetToolId() == ID_BUS_BUTT) && (aItem->Type() == SCH_LINE_T) ) + { + SCH_LINE* segment = (SCH_LINE*) aItem; + + if( segment->GetLayer() != LAYER_BUS ) + break; + + // Bus in progress: + OnLeftClick( aDC, aPosition ); + } + else if( (GetToolId() == ID_WIRE_BUTT ) && (aItem->Type() == SCH_LINE_T) ) + { + SCH_LINE* segment = (SCH_LINE*) aItem; + + if( segment->GetLayer() != LAYER_WIRE ) + break; + + // Wire in progress: + OnLeftClick( aDC, aPosition ); + } + } + break; + + case HK_COPY_COMPONENT_OR_LABEL: // Duplicate component or text/label + if( itemInEdit ) + break; + + if( aItem == NULL ) + { + aItem = LocateAndShowItem( aPosition, SCH_COLLECTOR::MovableItems ); + + if( aItem == NULL ) + break; + } + + cmd.SetId( hotKey->m_IdMenuEvent ); + wxPostEvent( this, cmd ); + break; + + case HK_DRAG: // Start drag + case HK_MOVE_COMPONENT_OR_ITEM: // Start move schematic item. + if( ! notBusy ) + break; + + // Fall through + case HK_EDIT: + // Edit schematic item. Do not allow sheet edition when mowing + // Because a sheet edition can be complex. + if( itemInEdit && screen->GetCurItem()->Type() == SCH_SHEET_T ) + break; + + // Fall through + case HK_EDIT_COMPONENT_VALUE: // Edit component value field. + case HK_EDIT_COMPONENT_REFERENCE: // Edit component value reference. + case HK_EDIT_COMPONENT_FOOTPRINT: // Edit component footprint field. + case HK_MIRROR_Y: // Mirror Y + case HK_MIRROR_X: // Mirror X + case HK_ORIENT_NORMAL_COMPONENT: // Orient 0, no mirror (Component) + case HK_ROTATE: // Rotate schematic item. + case HK_EDIT_COMPONENT_WITH_LIBEDIT: // Call Libedit and load the current component + { + // force a new item search on hot keys at current position, + // if there is no currently edited item, + // to avoid using a previously selected item + if( ! itemInEdit ) + screen->SetCurItem( NULL ); + EDA_HOTKEY_CLIENT_DATA data( aPosition ); + cmd.SetInt( hotKey->m_Idcommand ); + cmd.SetClientObject( &data ); + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + } + break; + } + + // Hot key handled. + return true; +} + + +EDA_HOTKEY* LIB_EDIT_FRAME::GetHotKeyDescription( int aCommand ) const +{ + EDA_HOTKEY* HK_Descr = GetDescriptorFromCommand( aCommand, common_Hotkey_List ); + + if( HK_Descr == NULL ) + HK_Descr = GetDescriptorFromCommand( aCommand, libEdit_Hotkey_List ); + + return HK_Descr; +} + + +bool LIB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem ) +{ + if( aHotKey == 0 ) + return false; + + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + + cmd.SetEventObject( this ); + + /* Convert lower to upper case (the usual toupper function has problem + * with non ascii codes like function keys */ + if( (aHotKey >= 'a') && (aHotKey <= 'z') ) + aHotKey += 'A' - 'a'; + + EDA_HOTKEY* hotKey = GetDescriptorFromHotkey( aHotKey, common_Hotkey_List ); + + if( hotKey == NULL ) + hotKey = GetDescriptorFromHotkey( aHotKey, libEdit_Hotkey_List ); + + if( hotKey == NULL ) + return false; + + bool itemInEdit = m_drawItem && m_drawItem->InEditMode(); + + bool blocInProgress = GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK; + + switch( hotKey->m_Idcommand ) + { + default: + case HK_NOT_FOUND: + return false; + + case HK_HELP: // Display Current hotkey list + DisplayHotkeyList( this, g_Libedit_Hokeys_Descr ); + break; + + case HK_RESET_LOCAL_COORD: // Reset the relative coord + GetScreen()->m_O_Curseur = GetCrossHairPosition(); + break; + + case HK_LEFT_CLICK: + OnLeftClick( aDC, aPosition ); + break; + + case HK_LEFT_DCLICK: // Simulate a double left click: generate 2 events + OnLeftClick( aDC, aPosition ); + OnLeftDClick( aDC, aPosition ); + break; + + case HK_ZOOM_IN: + case HK_ZOOM_OUT: + case HK_ZOOM_REDRAW: + case HK_ZOOM_CENTER: + case HK_ZOOM_AUTO: + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_UNDO: + case HK_REDO: + if( !itemInEdit ) + { + cmd.SetId( hotKey->m_IdMenuEvent ); + GetEventHandler()->ProcessEvent( cmd ); + } + break; + + case HK_REPEAT_LAST: + if( ! itemInEdit ) + { + if( m_lastDrawItem && !m_lastDrawItem->InEditMode() && + ( m_lastDrawItem->Type() == LIB_PIN_T ) ) + RepeatPinItem( aDC, (LIB_PIN*) m_lastDrawItem ); + } + break; + + case HK_EDIT: + if( !itemInEdit ) + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem ) + { + switch( m_drawItem->Type() ) + { + case LIB_PIN_T: + cmd.SetId( ID_LIBEDIT_EDIT_PIN ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case LIB_ARC_T: + case LIB_CIRCLE_T: + case LIB_RECTANGLE_T: + case LIB_POLYLINE_T: + case LIB_TEXT_T: + cmd.SetId( ID_POPUP_LIBEDIT_BODY_EDIT_ITEM ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case LIB_FIELD_T: + cmd.SetId( ID_POPUP_LIBEDIT_FIELD_EDIT_ITEM ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + default: + break; + } + } + break; + + case HK_ROTATE: + if( blocInProgress ) + { + GetScreen()->m_BlockLocate.SetCommand( BLOCK_ROTATE ); + HandleBlockPlace( aDC ); + } + else + { + if( !itemInEdit ) + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem ) + { + cmd.SetId( ID_LIBEDIT_ROTATE_ITEM ); + GetEventHandler()->ProcessEvent( cmd ); + } + } + break; + + case HK_LIBEDIT_CREATE_PIN: + if( ! itemInEdit ) + { + SetToolID( ID_LIBEDIT_PIN_BUTT, wxCURSOR_PENCIL, _( "Add Pin" ) ); + OnLeftClick( aDC, aPosition ); + } + break; + + case HK_DELETE: + if( !itemInEdit ) + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem && !m_drawItem->InEditMode() ) + { + cmd.SetId( ID_POPUP_LIBEDIT_DELETE_ITEM ); + Process_Special_Functions( cmd ); + } + break; + + case HK_LIBEDIT_MOVE_GRAPHIC_ITEM: + if( !itemInEdit ) + { + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem ) + { + cmd.SetId( ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST ); + Process_Special_Functions( cmd ); + } + } + break; + + case HK_DRAG: + if( !itemInEdit ) + { + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem && !m_drawItem->InEditMode() ) + { + cmd.SetId( ID_POPUP_LIBEDIT_MODIFY_ITEM ); + Process_Special_Functions( cmd ); + } + } + break; + } + + // Hot key handled. + return true; +} + + +EDA_HOTKEY* LIB_VIEW_FRAME::GetHotKeyDescription( int aCommand ) const +{ + EDA_HOTKEY* HK_Descr = GetDescriptorFromCommand( aCommand, common_Hotkey_List ); + + if( HK_Descr == NULL ) + HK_Descr = GetDescriptorFromCommand( aCommand, viewlib_Hotkey_List ); + + return HK_Descr; +} + + +bool LIB_VIEW_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem ) +{ + if( aHotKey == 0 ) + return false; + + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + cmd.SetEventObject( this ); + + /* Convert lower to upper case (the usual toupper function has problem with non ascii + * codes like function keys */ + if( (aHotKey >= 'a') && (aHotKey <= 'z') ) + aHotKey += 'A' - 'a'; + + EDA_HOTKEY* HK_Descr = GetDescriptorFromHotkey( aHotKey, common_basic_Hotkey_List ); + + if( HK_Descr == NULL ) + HK_Descr = GetDescriptorFromHotkey( aHotKey, viewlib_Hotkey_List ); + + if( HK_Descr == NULL ) + return false; + + switch( HK_Descr->m_Idcommand ) + { + default: + case HK_NOT_FOUND: + return false; + + case HK_HELP: // Display Current hotkey list + DisplayHotkeyList( this, g_Viewlib_Hokeys_Descr ); + break; + + case HK_RESET_LOCAL_COORD: // set local (relative) coordinate origin + GetScreen()->m_O_Curseur = GetCrossHairPosition(); + break; + + case HK_LEFT_CLICK: + OnLeftClick( aDC, aPosition ); + break; + + case HK_LEFT_DCLICK: // Simulate a double left click: generate 2 events + OnLeftClick( aDC, aPosition ); + OnLeftDClick( aDC, aPosition ); + break; + + case HK_ZOOM_IN: + cmd.SetId( ID_POPUP_ZOOM_IN ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_ZOOM_OUT: + cmd.SetId( ID_POPUP_ZOOM_OUT ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_ZOOM_REDRAW: + cmd.SetId( ID_ZOOM_REDRAW ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_ZOOM_CENTER: + cmd.SetId( ID_POPUP_ZOOM_CENTER ); + GetEventHandler()->ProcessEvent( cmd ); + break; + + case HK_ZOOM_AUTO: + cmd.SetId( ID_ZOOM_PAGE ); + GetEventHandler()->ProcessEvent( cmd ); + break; + } + + return true; +} diff --git a/eeschema/hotkeys.h b/eeschema/hotkeys.h new file mode 100644 index 00000000..afcebcac --- /dev/null +++ b/eeschema/hotkeys.h @@ -0,0 +1,96 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 + */ + +/** + * eeschema/hotkeys.h + */ +#ifndef EESCHEMA_KOTKEYS_H_ +#define EESCHEMA_KOTKEYS_H_ + +#include + +// List of hot keys id. +// see also enum common_hotkey_id_commnand in hotkeys_basic.h +// for shared hotkeys id +enum hotkey_id_commnand { + HK_FIND_NEXT_ITEM = HK_COMMON_END, + HK_FIND_NEXT_DRC_MARKER, + HK_FIND_ITEM, + HK_FIND_REPLACE, + HK_DELETE, + HK_REPEAT_LAST, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM, + HK_MOVEBLOCK_TO_DRAGBLOCK, + HK_SAVE_BLOCK, + HK_LIBEDIT_CREATE_PIN, + HK_DELETE_PIN, + HK_ROTATE, + HK_EDIT, + HK_EDIT_COMPONENT_VALUE, + HK_EDIT_COMPONENT_REFERENCE, + HK_EDIT_COMPONENT_FOOTPRINT, + HK_EDIT_COMPONENT_WITH_LIBEDIT, + HK_MIRROR_X, + HK_MIRROR_Y, + HK_ORIENT_NORMAL_COMPONENT, + HK_MOVE_COMPONENT_OR_ITEM, + HK_COPY_COMPONENT_OR_LABEL, + HK_DRAG, + HK_ADD_NEW_COMPONENT, + HK_ADD_NEW_POWER, + HK_BEGIN_WIRE, + HK_BEGIN_BUS, + HK_END_CURR_LINEWIREBUS, + HK_ADD_WIRE_ENTRY, + HK_ADD_BUS_ENTRY, + HK_ADD_LABEL, + HK_ADD_HLABEL, + HK_ADD_GLABEL, + HK_ADD_JUNCTION, + HK_ADD_HIER_SHEET, + HK_ADD_GRAPHIC_TEXT, + HK_ADD_GRAPHIC_POLYLINE, + HK_ADD_NOCONN_FLAG, + HK_SAVE_LIB, + HK_SAVE_SCH, + HK_LOAD_SCH, + HK_LEFT_CLICK, + HK_LEFT_DCLICK, + HK_LEAVE_SHEET, + HK_DELETE_NODE +}; + +// List of hotkey descriptors for Eeschema +extern struct EDA_HOTKEY_CONFIG g_Eeschema_Hokeys_Descr[]; + +// List of hotkey descriptors for the schematic editor only +extern struct EDA_HOTKEY_CONFIG g_Schematic_Hokeys_Descr[]; + +// List of hotkey descriptors for the lib editor only +extern struct EDA_HOTKEY_CONFIG g_Libedit_Hokeys_Descr[]; + +// List of hotkey descriptors for the lib browser only +extern struct EDA_HOTKEY_CONFIG g_Viewlib_Hokeys_Descr[]; + +#endif // EESCHEMA_KOTKEYS_H_ diff --git a/eeschema/invoke_sch_dialog.h b/eeschema/invoke_sch_dialog.h new file mode 100644 index 00000000..fe36a41f --- /dev/null +++ b/eeschema/invoke_sch_dialog.h @@ -0,0 +1,97 @@ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2013 KiCad Developers, see change_log.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 + */ + +// This header is an insolation layer between top most frames and any number of +// DIALOG classes which can be called from a frame window. +// It is a place to put invocation functions for [modal] dialogs, with benefits: +// +// 1) The information about each dialog class is not exposed to the frame. +// So therefore the DIALOG class can often be kept out of a header file entirely. +// +// 2) The information about the calling frame is not necessarily exposed to +// to the called dialog class, at least not in here. + +// The actual InvokeDialog() function is usually coded at the bottom of the +// DIALOG_.cpp file. + + +#ifndef INVOKE_SCH_DIALOG_H_ +#define INVOKE_SCH_DIALOG_H_ + +#include +#include + +class wxFrame; +class wxDialog; +class LIB_PART; +class PART_LIBS; +class SCH_COMPONENT; +class RESCUER; + +// Often this is not used in the prototypes, since wxFrame is good enough and would +// represent maximum information hiding. +class SCH_EDIT_FRAME; + +/** + * Function InvokeDialogRescueEach + * This dialog asks the user which rescuable, cached parts he wants to rescue. + * Any rejects will be pruned from aCandidates. + * @param aCaller - the SCH_EDIT_FRAME calling this + * @param aRescuer - the active RESCUER instance + * @param aAskShowAgain - if true, a "Never Show Again" button will be included + */ +int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, RESCUER& aRescuer, bool aAskShowAgain ); + +/// Create and show DIALOG_ANNOTATE and return whatever +/// DIALOG_ANNOTATE::ShowModal() returns. +int InvokeDialogAnnotate( SCH_EDIT_FRAME* aCaller, wxString message = "" ); + +/// Create the modeless DIALOG_ERC and show it, return something to +/// destroy or close it. The dialog will have ID_DIALOG_ERC from id.h +wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller ); + +/// Create and show DIALOG_PRINT_USING_PRINTER and return whatever +/// DIALOG_PRINT_USING_PRINTER::ShowModal() returns. +int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller ); + +/// Create and show DIALOG_BOM and return whatever +/// DIALOG_BOM::ShowModal() returns. +int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller ); + +/** + * Function InvokeDialogNetList + * creates and shows NETLIST_DIALOG and returns whatever + * NETLIST_DIALOG::ShowModal() returns. + * @param int - NET_PLUGIN_CHANGE means user added or deleted a plugin, + * wxID_OK, or wxID_CANCEL. +*/ +#define NET_PLUGIN_CHANGE 1 +int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller ); + +bool InvokeEeschemaConfig( wxWindow* aParent, + wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames ); + + +#endif // INVOKE_SCH_DIALOG_H_ diff --git a/eeschema/lib_arc.cpp b/eeschema/lib_arc.cpp new file mode 100644 index 00000000..68f52ef4 --- /dev/null +++ b/eeschema/lib_arc.cpp @@ -0,0 +1,825 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_arc.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Helper function +static inline wxPoint twoPointVector( const wxPoint &startPoint, const wxPoint &endPoint ) +{ + return endPoint - startPoint; +} + + +//! @brief Given three points A B C, compute the circumcenter of the resulting triangle +//! reference: http://en.wikipedia.org/wiki/Circumscribed_circle +//! Coordinates of circumcenter in Cartesian coordinates +static wxPoint calcCenter( const wxPoint& A, const wxPoint& B, const wxPoint& C ) +{ + double circumCenterX, circumCenterY; + double Ax = (double) A.x; + double Ay = (double) A.y; + double Bx = (double) B.x; + double By = (double) B.y; + double Cx = (double) C.x; + double Cy = (double) C.y; + + wxPoint circumCenter; + + double D = 2.0 * ( Ax * ( By - Cy ) + Bx * ( Cy - Ay ) + Cx * ( Ay - By ) ); + + // prevent division / 0 + if( fabs( D ) < 1e-7 ) + D = 1e-7; + + circumCenterX = ( (Ay * Ay + Ax * Ax) * (By - Cy) + + (By * By + Bx * Bx) * (Cy - Ay) + + (Cy * Cy + Cx * Cx) * (Ay - By) ) / D; + + circumCenterY = ( (Ay * Ay + Ax * Ax) * (Cx - Bx) + + (By * By + Bx * Bx) * (Ax - Cx) + + (Cy * Cy + Cx * Cx) * (Bx - Ax) ) / D; + + circumCenter.x = (int) circumCenterX; + circumCenter.y = (int) circumCenterY; + + return circumCenter; +} + + +LIB_ARC::LIB_ARC( LIB_PART* aParent ) : LIB_ITEM( LIB_ARC_T, aParent ) +{ + m_Radius = 0; + m_t1 = 0; + m_t2 = 0; + m_Width = 0; + m_Fill = NO_FILL; + m_isFillable = true; + m_typeName = _( "Arc" ); + m_editState = 0; + m_lastEditState = 0; + m_editCenterDistance = 0.0; + m_editSelectPoint = ARC_STATUS_START; + m_editDirection = 0; +} + + +bool LIB_ARC::Save( OUTPUTFORMATTER& aFormatter ) +{ + int x1 = m_t1; + + if( x1 > 1800 ) + x1 -= 3600; + + int x2 = m_t2; + + if( x2 > 1800 ) + x2 -= 3600; + + aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n", + m_Pos.x, m_Pos.y, m_Radius, x1, x2, m_Unit, m_Convert, m_Width, + fill_tab[m_Fill], m_ArcStart.x, m_ArcStart.y, m_ArcEnd.x, + m_ArcEnd.y ); + + return true; +} + + +bool LIB_ARC::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + int startx, starty, endx, endy, cnt; + char tmp[256] = ""; + char* line = (char*) aLineReader; + + cnt = sscanf( line + 2, "%d %d %d %d %d %d %d %d %255s %d %d %d %d", + &m_Pos.x, &m_Pos.y, &m_Radius, &m_t1, &m_t2, &m_Unit, + &m_Convert, &m_Width, tmp, &startx, &starty, &endx, &endy ); + if( cnt < 8 ) + { + aErrorMsg.Printf( _( "Arc only had %d parameters of the required 8" ), cnt ); + return false; + } + + if( tmp[0] == 'F' ) + m_Fill = FILLED_SHAPE; + + if( tmp[0] == 'f' ) + m_Fill = FILLED_WITH_BG_BODYCOLOR; + + NORMALIZE_ANGLE_POS( m_t1 ); + NORMALIZE_ANGLE_POS( m_t2 ); + + // Actual Coordinates of arc ends are read from file + if( cnt >= 13 ) + { + m_ArcStart.x = startx; + m_ArcStart.y = starty; + m_ArcEnd.x = endx; + m_ArcEnd.y = endy; + } + else + { + // Actual Coordinates of arc ends are not read from file + // (old library), calculate them + m_ArcStart.x = m_Radius; + m_ArcStart.y = 0; + m_ArcEnd.x = m_Radius; + m_ArcEnd.y = 0; + RotatePoint( &m_ArcStart.x, &m_ArcStart.y, -m_t1 ); + m_ArcStart.x += m_Pos.x; + m_ArcStart.y += m_Pos.y; + RotatePoint( &m_ArcEnd.x, &m_ArcEnd.y, -m_t2 ); + m_ArcEnd.x += m_Pos.x; + m_ArcEnd.y += m_Pos.y; + } + + return true; +} + + +bool LIB_ARC::HitTest( const wxPoint& aRefPoint ) const +{ + int mindist = GetPenSize() / 2; + + // Have a minimal tolerance for hit test + if( mindist < MINIMUM_SELECTION_DISTANCE ) + mindist = MINIMUM_SELECTION_DISTANCE; + + return HitTest( aRefPoint, mindist, DefaultTransform ); +} + + +bool LIB_ARC::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + + if( aThreshold < 0 ) + aThreshold = GetPenSize() / 2; + + // TODO: use aTransMat to calculates parameters + wxPoint relativePosition = aPosition; + + relativePosition.y = -relativePosition.y; // reverse Y axis + + int distance = KiROUND( GetLineLength( m_Pos, relativePosition ) ); + + if( abs( distance - m_Radius ) > aThreshold ) + return false; + + // We are on the circle, ensure we are only on the arc, i.e. between + // m_ArcStart and m_ArcEnd + + wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd); + wxPoint startRelativePositionVector = twoPointVector( m_ArcStart, relativePosition ); + + wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart ); + wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd ); + wxPoint centerRelativePositionVector = twoPointVector( m_Pos, relativePosition ); + + // Compute the cross product to check if the point is in the sector + double crossProductStart = CrossProduct( centerStartVector, centerRelativePositionVector ); + double crossProductEnd = CrossProduct( centerEndVector, centerRelativePositionVector ); + + // The cross products need to be exchanged, depending on which side the center point + // relative to the start point to end point vector lies + if( CrossProduct( startEndVector, startRelativePositionVector ) < 0 ) + { + std::swap( crossProductStart, crossProductEnd ); + } + + // When the cross products have a different sign, the point lies in sector + // also check, if the reference is near start or end point + return HitTestPoints( m_ArcStart, relativePosition, MINIMUM_SELECTION_DISTANCE ) || + HitTestPoints( m_ArcEnd, relativePosition, MINIMUM_SELECTION_DISTANCE ) || + ( crossProductStart <= 0 && crossProductEnd >= 0 ); +} + + +EDA_ITEM* LIB_ARC::Clone() const +{ + return new LIB_ARC( *this ); +} + + +int LIB_ARC::compare( const LIB_ITEM& aOther ) const +{ + wxASSERT( aOther.Type() == LIB_ARC_T ); + + const LIB_ARC* tmp = ( LIB_ARC* ) &aOther; + + if( m_Pos.x != tmp->m_Pos.x ) + return m_Pos.x - tmp->m_Pos.x; + + if( m_Pos.y != tmp->m_Pos.y ) + return m_Pos.y - tmp->m_Pos.y; + + if( m_t1 != tmp->m_t1 ) + return m_t1 - tmp->m_t1; + + if( m_t2 != tmp->m_t2 ) + return m_t2 - tmp->m_t2; + + return 0; +} + + +void LIB_ARC::SetOffset( const wxPoint& aOffset ) +{ + m_Pos += aOffset; + m_ArcStart += aOffset; + m_ArcEnd += aOffset; +} + + +bool LIB_ARC::Inside( EDA_RECT& aRect ) const +{ + return aRect.Contains( m_ArcStart.x, -m_ArcStart.y ) + || aRect.Contains( m_ArcEnd.x, -m_ArcEnd.y ); +} + + +void LIB_ARC::Move( const wxPoint& aPosition ) +{ + wxPoint offset = aPosition - m_Pos; + m_Pos = aPosition; + m_ArcStart += offset; + m_ArcEnd += offset; +} + + +void LIB_ARC::MirrorHorizontal( const wxPoint& aCenter ) +{ + m_Pos.x -= aCenter.x; + m_Pos.x *= -1; + m_Pos.x += aCenter.x; + m_ArcStart.x -= aCenter.x; + m_ArcStart.x *= -1; + m_ArcStart.x += aCenter.x; + m_ArcEnd.x -= aCenter.x; + m_ArcEnd.x *= -1; + m_ArcEnd.x += aCenter.x; + std::swap( m_ArcStart, m_ArcEnd ); + std::swap( m_t1, m_t2 ); + m_t1 = 1800 - m_t1; + m_t2 = 1800 - m_t2; + if( m_t1 > 3600 || m_t2 > 3600 ) + { + m_t1 -= 3600; + m_t2 -= 3600; + } + else if( m_t1 < -3600 || m_t2 < -3600 ) + { + m_t1 += 3600; + m_t2 += 3600; + } +} + +void LIB_ARC::MirrorVertical( const wxPoint& aCenter ) +{ + m_Pos.y -= aCenter.y; + m_Pos.y *= -1; + m_Pos.y += aCenter.y; + m_ArcStart.y -= aCenter.y; + m_ArcStart.y *= -1; + m_ArcStart.y += aCenter.y; + m_ArcEnd.y -= aCenter.y; + m_ArcEnd.y *= -1; + m_ArcEnd.y += aCenter.y; + std::swap( m_ArcStart, m_ArcEnd ); + std::swap( m_t1, m_t2 ); + m_t1 = - m_t1; + m_t2 = - m_t2; + if( m_t1 > 3600 || m_t2 > 3600 ) + { + m_t1 -= 3600; + m_t2 -= 3600; + } + else if( m_t1 < -3600 || m_t2 < -3600 ) + { + m_t1 += 3600; + m_t2 += 3600; + } +} + +void LIB_ARC::Rotate( const wxPoint& aCenter, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + RotatePoint( &m_Pos, aCenter, rot_angle ); + RotatePoint( &m_ArcStart, aCenter, rot_angle ); + RotatePoint( &m_ArcEnd, aCenter, rot_angle ); + m_t1 -= rot_angle; + m_t2 -= rot_angle; + if( m_t1 > 3600 || m_t2 > 3600 ) + { + m_t1 -= 3600; + m_t2 -= 3600; + } + else if( m_t1 < -3600 || m_t2 < -3600 ) + { + m_t1 += 3600; + m_t2 += 3600; + } +} + + + +void LIB_ARC::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + int t1 = m_t1; + int t2 = m_t2; + wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; + + aTransform.MapAngles( &t1, &t2 ); + + if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR ) + { + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + aPlotter->Arc( pos, -t2, -t1, m_Radius, FILLED_SHAPE, 0 ); + } + + bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR; + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + aPlotter->Arc( pos, -t2, -t1, m_Radius, already_filled ? NO_FILL : m_Fill, GetPenSize() ); +} + + +int LIB_ARC::GetPenSize() const +{ + return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width; +} + + +void LIB_ARC::drawEditGraphics( EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor ) +{ + // The edit indicators only get drawn when a new arc is being drawn. + if( !IsNew() ) + return; + + // Use the last edit state so when the drawing switches from the end mode to the center + // point mode, the last line between the center points gets erased. + if( m_lastEditState == 1 ) + { + GRLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_ArcEnd.x, -m_ArcEnd.y, 0, aColor ); + } + else + { + GRDashedLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_Pos.x, -m_Pos.y, 0, aColor ); + GRDashedLine( aClipBox, aDC, m_ArcEnd.x, -m_ArcEnd.y, m_Pos.x, -m_Pos.y, 0, aColor ); + } +} + + +void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + // Don't draw the arc until the end point is selected. Only the edit indicators + // get drawn at this time. + if( IsNew() && m_lastEditState == 1 ) + return; + + wxPoint pos1, pos2, posc; + EDA_COLOR_T color = GetLayerColor( LAYER_DEVICE ); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset; + pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset; + posc = aTransform.TransformCoordinate( m_Pos ) + aOffset; + int pt1 = m_t1; + int pt2 = m_t2; + bool swap = aTransform.MapAngles( &pt1, &pt2 ); + + if( swap ) + { + std::swap( pos1.x, pos2.x ); + std::swap( pos1.y, pos2.y ); + } + + GRSetDrawMode( aDC, aDrawMode ); + + FILL_T fill = aData ? NO_FILL : m_Fill; + + if( aColor >= 0 ) + fill = NO_FILL; + + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; + + if( fill == FILLED_WITH_BG_BODYCOLOR ) + { + GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, + m_Radius, GetPenSize( ), + (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), + GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + } + else if( fill == FILLED_SHAPE && !aData ) + { + GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius, + color, color ); + } + else + { + +#ifdef DRAW_ARC_WITH_ANGLE + + GRArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius, + GetPenSize(), color ); +#else + + GRArc1( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, + posc.x, posc.y, GetPenSize(), color ); +#endif + } + + /* Set to one (1) to draw bounding box around arc to validate bounding box + * calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +const EDA_RECT LIB_ARC::GetBoundingBox() const +{ + int minX, minY, maxX, maxY, angleStart, angleEnd; + EDA_RECT rect; + wxPoint nullPoint, startPos, endPos, centerPos; + wxPoint normStart = m_ArcStart - m_Pos; + wxPoint normEnd = m_ArcEnd - m_Pos; + + if( ( normStart == nullPoint ) || ( normEnd == nullPoint ) || ( m_Radius == 0 ) ) + { + wxLogDebug( wxT("Invalid arc drawing definition, center(%d, %d) \ +start(%d, %d), end(%d, %d), radius %d" ), + m_Pos.x, m_Pos.y, m_ArcStart.x, m_ArcStart.y, m_ArcEnd.x, + m_ArcEnd.y, m_Radius ); + return rect; + } + + endPos = DefaultTransform.TransformCoordinate( m_ArcEnd ); + startPos = DefaultTransform.TransformCoordinate( m_ArcStart ); + centerPos = DefaultTransform.TransformCoordinate( m_Pos ); + angleStart = m_t1; + angleEnd = m_t2; + + if( DefaultTransform.MapAngles( &angleStart, &angleEnd ) ) + { + std::swap( endPos.x, startPos.x ); + std::swap( endPos.y, startPos.y ); + } + + /* Start with the start and end point of the arc. */ + minX = std::min( startPos.x, endPos.x ); + minY = std::min( startPos.y, endPos.y ); + maxX = std::max( startPos.x, endPos.x ); + maxY = std::max( startPos.y, endPos.y ); + + /* Zero degrees is a special case. */ + if( angleStart == 0 ) + maxX = centerPos.x + m_Radius; + + /* Arc end angle wrapped passed 360. */ + if( angleStart > angleEnd ) + angleEnd += 3600; + + if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */ + maxY = centerPos.y + m_Radius; + + if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */ + minX = centerPos.x - m_Radius; + + if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */ + minY = centerPos.y - m_Radius; + + if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */ + maxX = centerPos.x + m_Radius; + + rect.SetOrigin( minX, minY ); + rect.SetEnd( maxX, maxY ); + rect.Inflate( ( GetPenSize()+1 ) / 2 ); + + return rect; +} + + +void LIB_ARC::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) +{ + wxString msg; + EDA_RECT bBox = GetBoundingBox(); + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Width, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); + + msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, + bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y ); + + aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) ); +} + + +wxString LIB_ARC::GetSelectMenuText() const +{ + return wxString::Format( _( "Arc center (%s, %s), radius %s" ), + GetChars( CoordinateToString( m_Pos.x ) ), + GetChars( CoordinateToString( m_Pos.y ) ), + GetChars( CoordinateToString( m_Radius ) ) ); +} + + +void LIB_ARC::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Invalid edit mode for LIB_ARC object." ) ); + + if( aEditMode == IS_NEW ) + { + m_ArcStart = m_ArcEnd = aPosition; + m_editState = m_lastEditState = 1; + } + else if( aEditMode == IS_MOVED ) + { + m_initialPos = m_Pos; + m_initialCursorPos = aPosition; + SetEraseLastDrawItem(); + } + else + { + // The arc center point has to be rotated with while adjusting the + // start or end point, determine the side of this point and the distance + // from the start / end point + wxPoint middlePoint = wxPoint( (m_ArcStart.x + m_ArcEnd.x) / 2, + (m_ArcStart.y + m_ArcEnd.y) / 2 ); + wxPoint centerVector = m_Pos - middlePoint; + wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd ); + m_editCenterDistance = EuclideanNorm( centerVector ); + + // Determine on which side is the center point + m_editDirection = CrossProduct( startEndVector, centerVector ) ? 1 : -1; + + // Drag either the start, end point or the outline + if( HitTestPoints( m_ArcStart, aPosition, MINIMUM_SELECTION_DISTANCE ) ) + { + m_editSelectPoint = ARC_STATUS_START; + } + else if( HitTestPoints( m_ArcEnd, aPosition, MINIMUM_SELECTION_DISTANCE ) ) + { + m_editSelectPoint = ARC_STATUS_END; + } + else + { + m_editSelectPoint = ARC_STATUS_OUTLINE; + } + + m_editState = 0; + SetEraseLastDrawItem(); + } + + m_Flags = aEditMode; +} + + +bool LIB_ARC::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). LIB_ARC is not being edited." ) ); + + if( m_Flags == IS_NEW ) + { + if( m_editState == 1 ) // Second position yields the arc segment length. + { + m_ArcEnd = aPosition; + m_editState = 2; + SetEraseLastDrawItem( false ); + return true; // Need third position to calculate center point. + } + } + + return false; +} + + +void LIB_ARC::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Bad call to EndEdit(). LIB_ARC is not being edited." ) ); + + SetEraseLastDrawItem( false ); + m_lastEditState = 0; + m_editState = 0; + m_Flags = 0; +} + + +void LIB_ARC::calcEdit( const wxPoint& aPosition ) +{ + if( m_Flags == IS_RESIZED ) + { + wxPoint newCenterPoint, startPos, endPos; + + // Choose the point of the arc to be adjusted + if( m_editSelectPoint == ARC_STATUS_START ) + { + startPos = aPosition; + endPos = m_ArcEnd; + } + else if( m_editSelectPoint == ARC_STATUS_END ) + { + endPos = aPosition; + startPos = m_ArcStart; + } + else + { + // Use the cursor for adjusting the arc curvature + startPos = m_ArcStart; + endPos = m_ArcEnd; + + // If the distance is too small, use the old center point + // else the new center point is calculated over the three points start/end/cursor + if( DistanceLinePoint( startPos, endPos, aPosition ) > MINIMUM_SELECTION_DISTANCE ) + { + newCenterPoint = calcCenter( startPos, aPosition, endPos ); + } + else + { + newCenterPoint = m_Pos; + } + + // Determine if the arc angle is larger than 180 degrees -> this happens if both + // points (cursor position, center point) lie on the same side of the vector + // start-end + double crossA = CrossProduct( twoPointVector( startPos, endPos ), + twoPointVector( endPos, aPosition ) ); + double crossB = CrossProduct( twoPointVector( startPos, endPos ), + twoPointVector( endPos, newCenterPoint ) ); + + if( ( crossA < 0 && crossB < 0 ) || ( crossA >= 0 && crossB >= 0 ) ) + newCenterPoint = m_Pos; + } + + if( m_editSelectPoint == ARC_STATUS_START || m_editSelectPoint == ARC_STATUS_END ) + { + // Compute the new center point when the start/end points are modified + wxPoint middlePoint = wxPoint( (startPos.x + endPos.x) / 2, + (startPos.y + endPos.y) / 2 ); + + wxPoint startEndVector = twoPointVector( startPos, endPos ); + wxPoint perpendicularVector = wxPoint( -startEndVector.y, startEndVector.x ); + double lengthPerpendicularVector = EuclideanNorm( perpendicularVector ); + + // prevent too large values, division / 0 + if( lengthPerpendicularVector < 1e-1 ) + lengthPerpendicularVector = 1e-1; + + perpendicularVector.x = (int) ( (double) perpendicularVector.x * + m_editCenterDistance / + lengthPerpendicularVector ) * m_editDirection; + perpendicularVector.y = (int) ( (double) perpendicularVector.y * + m_editCenterDistance / + lengthPerpendicularVector ) * m_editDirection; + + newCenterPoint = middlePoint + perpendicularVector; + + m_ArcStart = startPos; + m_ArcEnd = endPos; + } + + m_Pos = newCenterPoint; + calcRadiusAngles(); + } + else if( m_Flags == IS_NEW ) + { + if( m_editState == 1 ) + { + m_ArcEnd = aPosition; + } + + if( m_editState != m_lastEditState ) + m_lastEditState = m_editState; + + // Keep the arc center point up to date. Otherwise, there will be edit graphic + // artifacts left behind from the initial draw. + int dx, dy; + int cX, cY; + double angle; + + cX = aPosition.x; + cY = aPosition.y; + + dx = m_ArcEnd.x - m_ArcStart.x; + dy = m_ArcEnd.y - m_ArcStart.y; + cX -= m_ArcStart.x; + cY -= m_ArcStart.y; + angle = ArcTangente( dy, dx ); + RotatePoint( &dx, &dy, angle ); /* The segment dx, dy is horizontal + * -> Length = dx, dy = 0 */ + RotatePoint( &cX, &cY, angle ); + cX = dx / 2; /* cX, cY is on the median segment 0.0 a dx, 0 */ + + RotatePoint( &cX, &cY, -angle ); + cX += m_ArcStart.x; + cY += m_ArcStart.y; + m_Pos.x = cX; + m_Pos.y = cY; + calcRadiusAngles(); + + SetEraseLastDrawItem(); + } + else if( m_Flags == IS_MOVED ) + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} + + +void LIB_ARC::calcRadiusAngles() +{ + wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart ); + wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd ); + + m_Radius = KiROUND( EuclideanNorm( centerStartVector ) ); + + // Angles in eeschema are still integers + m_t1 = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) ); + m_t2 = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) ); + + NORMALIZE_ANGLE_POS( m_t1 ); + NORMALIZE_ANGLE_POS( m_t2 ); // angles = 0 .. 3600 + + // Restrict angle to less than 180 to avoid PBS display mirror Trace because it is + // assumed that the arc is less than 180 deg to find orientation after rotate or mirror. + if( (m_t2 - m_t1) > 1800 ) + m_t2 -= 3600; + else if( (m_t2 - m_t1) <= -1800 ) + m_t2 += 3600; + + while( (m_t2 - m_t1) >= 1800 ) + { + m_t2--; + m_t1++; + } + + while( (m_t1 - m_t2) >= 1800 ) + { + m_t2++; + m_t1--; + } + + NORMALIZE_ANGLE_POS( m_t1 ); + + if( !IsMoving() ) + NORMALIZE_ANGLE_POS( m_t2 ); +} diff --git a/eeschema/lib_arc.h b/eeschema/lib_arc.h new file mode 100644 index 00000000..dcebbdfb --- /dev/null +++ b/eeschema/lib_arc.h @@ -0,0 +1,161 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_arc.h + */ + +#ifndef _LIB_ARC_H_ +#define _LIB_ARC_H_ + +#include + + +class TRANSFORM; + + +class LIB_ARC : public LIB_ITEM +{ + enum SELECT_T // When creating an arc: status of arc + { + ARC_STATUS_START, + ARC_STATUS_END, + ARC_STATUS_OUTLINE, + }; + + int m_Radius; + int m_t1; // First radius angle of the arc in 0.1 degrees. + int m_t2; /* Second radius angle of the arc in 0.1 degrees. */ + wxPoint m_ArcStart; + wxPoint m_ArcEnd; /* Arc end position. */ + wxPoint m_Pos; /* Radius center point. */ + int m_Width; /* Line width */ + double m_editCenterDistance; + SELECT_T m_editSelectPoint; + int m_editState; + int m_editDirection; + int m_lastEditState; + + /** + * Draws the arc. + */ + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + /** + * Draw the graphics when the arc is being edited. + */ + void drawEditGraphics( EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor ); + + /** + * Calculates the center, radius, and angles at \a aPosition when the arc is being edited. + * + * Note: The center may not necessarily be on the grid. + * + * @param aPosition - The current mouse position in drawing coordinates. + */ + void calcEdit( const wxPoint& aPosition ); + + /** + * Calculate the radius and angle of an arc using the start, end, and center points. + */ + void calcRadiusAngles(); + +public: + LIB_ARC( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_ARC() { } + + wxString GetClass() const + { + return wxT( "LIB_ARC" ); + } + + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint& aPosition, int aThreshold, const TRANSFORM& aTransform ) const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + int GetPenSize() const; + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_Pos; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Width; } + + void SetWidth( int aWidth ) { m_Width = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_arc_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The arc specific sort order is as follows: + * - Arc horizontal (X) position. + * - Arc vertical (Y) position. + * - Arc start angle. + * - Arc end angle. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_ARC_H_ diff --git a/eeschema/lib_bezier.cpp b/eeschema/lib_bezier.cpp new file mode 100644 index 00000000..35c31878 --- /dev/null +++ b/eeschema/lib_bezier.cpp @@ -0,0 +1,421 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_bezier.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +LIB_BEZIER::LIB_BEZIER( LIB_PART* aParent ) : + LIB_ITEM( LIB_BEZIER_T, aParent ) +{ + m_Fill = NO_FILL; + m_Width = 0; + m_isFillable = true; + m_typeName = _( "Bezier" ); +} + + +bool LIB_BEZIER::Save( OUTPUTFORMATTER& aFormatter ) +{ + int ccount = GetCornerCount(); + + aFormatter.Print( 0, "B %d %d %d %d", ccount, m_Unit, m_Convert, m_Width ); + + for( unsigned i = 0; i < GetCornerCount(); i++ ) + { + aFormatter.Print( 0, " %d %d", m_BezierPoints[i].x, m_BezierPoints[i].y ); + } + + aFormatter.Print( 0, " %c\n", fill_tab[m_Fill] ); + + return true; +} + + +bool LIB_BEZIER::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char* p; + int i, ccount = 0; + wxPoint pt; + char* line = (char*) aLineReader; + + i = sscanf( line + 2, "%d %d %d %d", &ccount, &m_Unit, &m_Convert, &m_Width ); + + if( i !=4 ) + { + aErrorMsg.Printf( _( "Bezier only had %d parameters of the required 4" ), i ); + return false; + } + + if( ccount <= 0 ) + { + aErrorMsg.Printf( _( "Bezier count parameter %d is invalid" ), ccount ); + return false; + } + + strtok( line + 2, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); + + for( i = 0; i < ccount; i++ ) + { + p = strtok( NULL, " \t\n" ); + + if( sscanf( p, "%d", &pt.x ) != 1 ) + { + aErrorMsg.Printf( _( "Bezier point %d X position not defined" ), i ); + return false; + } + + p = strtok( NULL, " \t\n" ); + + if( sscanf( p, "%d", &pt.y ) != 1 ) + { + aErrorMsg.Printf( _( "Bezier point %d Y position not defined" ), i ); + return false; + } + + m_BezierPoints.push_back( pt ); + } + + m_Fill = NO_FILL; + + if( ( p = strtok( NULL, " \t\n" ) ) != NULL ) + { + if( p[0] == 'F' ) + m_Fill = FILLED_SHAPE; + + if( p[0] == 'f' ) + m_Fill = FILLED_WITH_BG_BODYCOLOR; + } + + return true; +} + + +EDA_ITEM* LIB_BEZIER::Clone() const +{ + return new LIB_BEZIER( *this ); +} + + +int LIB_BEZIER::compare( const LIB_ITEM& aOther ) const +{ + wxASSERT( aOther.Type() == LIB_BEZIER_T ); + + const LIB_BEZIER* tmp = ( LIB_BEZIER* ) &aOther; + + if( m_BezierPoints.size() != tmp->m_BezierPoints.size() ) + return m_BezierPoints.size() - tmp->m_BezierPoints.size(); + + for( size_t i = 0; i < m_BezierPoints.size(); i++ ) + { + if( m_BezierPoints[i].x != tmp->m_BezierPoints[i].x ) + return m_BezierPoints[i].x - tmp->m_BezierPoints[i].x; + + if( m_BezierPoints[i].y != tmp->m_BezierPoints[i].y ) + return m_BezierPoints[i].y - tmp->m_BezierPoints[i].y; + } + + return 0; +} + + +void LIB_BEZIER::SetOffset( const wxPoint& aOffset ) +{ + size_t i; + + for( i = 0; i < m_BezierPoints.size(); i++ ) + m_BezierPoints[i] += aOffset; + + for( i = 0; i < m_PolyPoints.size(); i++ ) + m_PolyPoints[i] += aOffset; +} + + +bool LIB_BEZIER::Inside( EDA_RECT& aRect ) const +{ + for( size_t i = 0; i < m_PolyPoints.size(); i++ ) + { + if( aRect.Contains( m_PolyPoints[i].x, -m_PolyPoints[i].y ) ) + return true; + } + + return false; +} + + +void LIB_BEZIER::Move( const wxPoint& aPosition ) +{ + SetOffset( aPosition - m_PolyPoints[0] ); +} + + +void LIB_BEZIER::MirrorHorizontal( const wxPoint& aCenter ) +{ + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_PolyPoints[i].x -= aCenter.x; + m_PolyPoints[i].x *= -1; + m_PolyPoints[i].x += aCenter.x; + } + + imax = m_BezierPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_BezierPoints[i].x -= aCenter.x; + m_BezierPoints[i].x *= -1; + m_BezierPoints[i].x += aCenter.x; + } +} + +void LIB_BEZIER::MirrorVertical( const wxPoint& aCenter ) +{ + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_PolyPoints[i].y -= aCenter.y; + m_PolyPoints[i].y *= -1; + m_PolyPoints[i].y += aCenter.y; + } + + imax = m_BezierPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_BezierPoints[i].y -= aCenter.y; + m_BezierPoints[i].y *= -1; + m_BezierPoints[i].y += aCenter.y; + } +} + +void LIB_BEZIER::Rotate( const wxPoint& aCenter, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + RotatePoint( &m_PolyPoints[i], aCenter, rot_angle ); + } + + imax = m_BezierPoints.size(); + + for( i = 0; i < imax; i++ ) + { + RotatePoint( &m_BezierPoints[i], aCenter, rot_angle ); + } +} + + +void LIB_BEZIER::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + static std::vector< wxPoint > cornerList; + cornerList.clear(); + + for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) + { + wxPoint pos = m_PolyPoints[ii]; + pos = aTransform.TransformCoordinate( pos ) + aOffset; + cornerList.push_back( pos ); + } + + if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR ) + { + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + aPlotter->PlotPoly( cornerList, FILLED_WITH_BG_BODYCOLOR, 0 ); + } + + bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR; + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + aPlotter->PlotPoly( cornerList, already_filled ? NO_FILL : m_Fill, GetPenSize() ); +} + + +int LIB_BEZIER::GetPenSize() const +{ + return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width; +} + + +void LIB_BEZIER::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + std::vector PolyPointsTraslated; + + EDA_COLOR_T color = GetLayerColor( LAYER_DEVICE ); + + m_PolyPoints = Bezier2Poly( m_BezierPoints[0], + m_BezierPoints[1], + m_BezierPoints[2], + m_BezierPoints[3] ); + + PolyPointsTraslated.clear(); + + for( unsigned int i = 0; i < m_PolyPoints.size() ; i++ ) + PolyPointsTraslated.push_back( aTransform.TransformCoordinate( m_PolyPoints[i] ) + + aOffset ); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + FILL_T fill = aData ? NO_FILL : m_Fill; + + if( aColor >= 0 ) + fill = NO_FILL; + + GRSetDrawMode( aDC, aDrawMode ); + + if( fill == FILLED_WITH_BG_BODYCOLOR ) + GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), + &PolyPointsTraslated[0], 1, GetPenSize(), + (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), + GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + else if( fill == FILLED_SHAPE ) + GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), + &PolyPointsTraslated[0], 1, GetPenSize(), color, color ); + else + GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), + &PolyPointsTraslated[0], 0, GetPenSize(), color, color ); + + /* Set to one (1) to draw bounding box around bezier curve to validate + * bounding box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + GRRect( aPanel->GetClipBox(), aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, + bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA ); +#endif +} + + +bool LIB_BEZIER::HitTest( const wxPoint& aRefPos ) const +{ + int mindist = GetPenSize() / 2; + + // Have a minimal tolerance for hit test + if ( mindist < MINIMUM_SELECTION_DISTANCE ) + mindist = MINIMUM_SELECTION_DISTANCE; + + return HitTest( aRefPos, mindist, DefaultTransform ); +} + + +bool LIB_BEZIER::HitTest( const wxPoint &aPosRef, int aThreshold, const TRANSFORM& aTransform ) const +{ + wxPoint start, end; + + if( aThreshold < 0 ) + aThreshold = GetPenSize() / 2; + + for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) + { + start = aTransform.TransformCoordinate( m_PolyPoints[ii - 1] ); + end = aTransform.TransformCoordinate( m_PolyPoints[ii] ); + + if ( TestSegmentHit( aPosRef, start, end, aThreshold ) ) + return true; + } + + return false; +} + + +const EDA_RECT LIB_BEZIER::GetBoundingBox() const +{ + EDA_RECT rect; + int xmin, xmax, ymin, ymax; + + if( !GetCornerCount() ) + return rect; + + xmin = xmax = m_PolyPoints[0].x; + ymin = ymax = m_PolyPoints[0].y; + + for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) + { + xmin = std::min( xmin, m_PolyPoints[ii].x ); + xmax = std::max( xmax, m_PolyPoints[ii].x ); + ymin = std::min( ymin, m_PolyPoints[ii].y ); + ymax = std::max( ymax, m_PolyPoints[ii].y ); + } + + rect.SetOrigin( xmin, ymin ); + rect.SetEnd( xmax, ymax ); + rect.Inflate( ( GetPenSize()+1 ) / 2 ); + + rect.RevertYAxis(); + + return rect; +} + + +void LIB_BEZIER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) +{ + wxString msg; + EDA_RECT bBox = GetBoundingBox(); + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Width, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); + + msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, + bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y ); + + aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) ); +} diff --git a/eeschema/lib_bezier.h b/eeschema/lib_bezier.h new file mode 100644 index 00000000..940b0542 --- /dev/null +++ b/eeschema/lib_bezier.h @@ -0,0 +1,119 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_bezier.h + */ + +#ifndef _LIB_BEZIER_H_ +#define _LIB_BEZIER_H_ + +#include + + +/** + * Class LIB_BEZIER + * defines bezier curve graphic body item. + */ +class LIB_BEZIER : public LIB_ITEM +{ + int m_Width; // Line width + std::vector m_BezierPoints; // list of parameter (3|4) + std::vector m_PolyPoints; // list of points (>= 2) + + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + +public: + LIB_BEZIER( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_BEZIER() { } + + wxString GetClass() const + { + return wxT( "LIB_BEZIER" ); + } + + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + void AddPoint( const wxPoint& aPoint ); + + void SetOffset( const wxPoint& aOffset ); + + /** + * @return the number of corners + */ + unsigned GetCornerCount() const { return m_PolyPoints.size(); } + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint& aPosRef, int aThreshold, const TRANSFORM& aTransform ) const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_PolyPoints[0]; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Width; } + + void SetWidth( int aWidth ) { m_Width = aWidth; } + + int GetPenSize( ) const; + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The bezier curve specific sort order for each curve segment point is as follows: + * - Bezier horizontal (X) point position. + * - Bezier vertical (Y) point position. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_BEZIER_H_ diff --git a/eeschema/lib_circle.cpp b/eeschema/lib_circle.cpp new file mode 100644 index 00000000..bcf6a404 --- /dev/null +++ b/eeschema/lib_circle.cpp @@ -0,0 +1,356 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_circle.cpp + * @brief LIB_CIRCLE class implementation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +LIB_CIRCLE::LIB_CIRCLE( LIB_PART* aParent ) : + LIB_ITEM( LIB_CIRCLE_T, aParent ) +{ + m_Radius = 0; + m_Width = 0; + m_Fill = NO_FILL; + m_isFillable = true; + m_typeName = _( "Circle" ); +} + + +bool LIB_CIRCLE::Save( OUTPUTFORMATTER& aFormatter ) +{ + aFormatter.Print( 0, "C %d %d %d %d %d %d %c\n", m_Pos.x, m_Pos.y, + m_Radius, m_Unit, m_Convert, m_Width, fill_tab[m_Fill] ); + + return true; +} + + +bool LIB_CIRCLE::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char tmp[256]; + char* line = (char*) aLineReader; + + int cnt = sscanf( line + 2, "%d %d %d %d %d %d %255s", &m_Pos.x, &m_Pos.y, + &m_Radius, &m_Unit, &m_Convert, &m_Width, tmp ); + + if( cnt < 6 ) + { + aErrorMsg.Printf( _( "Circle only had %d parameters of the required 6" ), cnt ); + return false; + } + + if( tmp[0] == 'F' ) + m_Fill = FILLED_SHAPE; + + if( tmp[0] == 'f' ) + m_Fill = FILLED_WITH_BG_BODYCOLOR; + + return true; +} + + +bool LIB_CIRCLE::HitTest( const wxPoint& aPosRef ) const +{ + int mindist = GetPenSize() / 2; + + // Have a minimal tolerance for hit test + if( mindist < MINIMUM_SELECTION_DISTANCE ) + mindist = MINIMUM_SELECTION_DISTANCE; + + return HitTest( aPosRef, mindist, DefaultTransform ); +} + + +bool LIB_CIRCLE::HitTest( const wxPoint &aPosRef, int aThreshold, const TRANSFORM& aTransform ) const +{ + if( aThreshold < 0 ) + aThreshold = GetPenSize() / 2; + + int dist = KiROUND( GetLineLength( aPosRef, aTransform.TransformCoordinate( m_Pos ) ) ); + + if( abs( dist - m_Radius ) <= aThreshold ) + return true; + return false; +} + + +EDA_ITEM* LIB_CIRCLE::Clone() const +{ + return new LIB_CIRCLE( *this ); +} + + +int LIB_CIRCLE::compare( const LIB_ITEM& aOther ) const +{ + wxASSERT( aOther.Type() == LIB_CIRCLE_T ); + + const LIB_CIRCLE* tmp = ( LIB_CIRCLE* ) &aOther; + + if( m_Pos.x != tmp->m_Pos.x ) + return m_Pos.x - tmp->m_Pos.x; + + if( m_Pos.y != tmp->m_Pos.y ) + return m_Pos.y - tmp->m_Pos.y; + + if( m_Radius != tmp->m_Radius ) + return m_Radius - tmp->m_Radius; + + return 0; +} + + +void LIB_CIRCLE::SetOffset( const wxPoint& aOffset ) +{ + m_Pos += aOffset; +} + + +bool LIB_CIRCLE::Inside( EDA_RECT& aRect ) const +{ + /* + * FIXME: This fails to take into account the radius around the center + * point. + */ + return aRect.Contains( m_Pos.x, -m_Pos.y ); +} + + +void LIB_CIRCLE::Move( const wxPoint& aPosition ) +{ + m_Pos = aPosition; +} + + +void LIB_CIRCLE::MirrorHorizontal( const wxPoint& aCenter ) +{ + m_Pos.x -= aCenter.x; + m_Pos.x *= -1; + m_Pos.x += aCenter.x; +} + + +void LIB_CIRCLE::MirrorVertical( const wxPoint& aCenter ) +{ + m_Pos.y -= aCenter.y; + m_Pos.y *= -1; + m_Pos.y += aCenter.y; +} + + +void LIB_CIRCLE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + + RotatePoint( &m_Pos, aCenter, rot_angle ); +} + + +void LIB_CIRCLE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; + + if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR ) + { + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + aPlotter->Circle( pos, m_Radius * 2, FILLED_SHAPE, 0 ); + } + + bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR; + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + aPlotter->Circle( pos, m_Radius * 2, already_filled ? NO_FILL : m_Fill, GetPenSize() ); +} + + +int LIB_CIRCLE::GetPenSize() const +{ + return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width; +} + + +void LIB_CIRCLE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + wxPoint pos1; + + EDA_COLOR_T color = GetLayerColor( LAYER_DEVICE ); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + pos1 = aTransform.TransformCoordinate( m_Pos ) + aOffset; + GRSetDrawMode( aDC, aDrawMode ); + + FILL_T fill = aData ? NO_FILL : m_Fill; + if( aColor >= 0 ) + fill = NO_FILL; + + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; + if( fill == FILLED_WITH_BG_BODYCOLOR ) + GRFilledCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), + (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), + GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + else if( fill == FILLED_SHAPE ) + GRFilledCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, 0, color, color ); + else + GRCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), color ); + + /* Set to one (1) to draw bounding box around circle to validate bounding + * box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +const EDA_RECT LIB_CIRCLE::GetBoundingBox() const +{ + EDA_RECT rect; + + rect.SetOrigin( m_Pos.x - m_Radius, m_Pos.y - m_Radius ); + rect.SetEnd( m_Pos.x + m_Radius, m_Pos.y + m_Radius ); + rect.Inflate( ( GetPenSize()+1 ) / 2 ); + + rect.RevertYAxis(); + + return rect; +} + + +void LIB_CIRCLE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + EDA_RECT bBox = GetBoundingBox(); + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Width, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); + + msg = StringFromValue( g_UserUnit, m_Radius, true ); + aList.push_back( MSG_PANEL_ITEM( _( "Radius" ), msg, RED ) ); + + msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, + bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y ); + + aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) ); +} + + +wxString LIB_CIRCLE::GetSelectMenuText() const +{ + return wxString::Format( _( "Circle center (%s, %s), radius %s" ), + GetChars( CoordinateToString( m_Pos.x ) ), + GetChars( CoordinateToString( m_Pos.y ) ), + GetChars( CoordinateToString( m_Radius ) ) ); +} + + +void LIB_CIRCLE::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Invalid edit mode for LIB_CIRCLE object." ) ); + + if( aEditMode == IS_NEW ) + { + m_Pos = m_initialPos = aPosition; + } + else if( aEditMode == IS_MOVED ) + { + m_initialPos = m_Pos; + m_initialCursorPos = aPosition; + SetEraseLastDrawItem(); + } + else if( aEditMode == IS_RESIZED ) + { + SetEraseLastDrawItem(); + } + + m_Flags = aEditMode; +} + + +bool LIB_CIRCLE::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). LIB_CIRCLE is not being edited." ) ); + + return false; +} + + +void LIB_CIRCLE::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Bad call to EndEdit(). LIB_CIRCLE is not being edited." ) ); + + SetEraseLastDrawItem( false ); + m_Flags = 0; +} + + +void LIB_CIRCLE::calcEdit( const wxPoint& aPosition ) +{ + if( m_Flags == IS_NEW || m_Flags == IS_RESIZED ) + { + if( m_Flags == IS_NEW ) + SetEraseLastDrawItem(); + + m_Radius = KiROUND( GetLineLength( m_Pos, aPosition ) ); + } + else + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} diff --git a/eeschema/lib_circle.h b/eeschema/lib_circle.h new file mode 100644 index 00000000..fe6ee3ce --- /dev/null +++ b/eeschema/lib_circle.h @@ -0,0 +1,121 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_circle.h + */ + +#ifndef _LIB_CIRCLE_H_ +#define _LIB_CIRCLE_H_ + +#include + + +class LIB_CIRCLE : public LIB_ITEM +{ + int m_Radius; + wxPoint m_Pos; // Position or centre (Arc and Circle) or start point (segments). + int m_Width; // Line width. + + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + void calcEdit( const wxPoint& aPosition ); + +public: + LIB_CIRCLE( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_CIRCLE() { } + + wxString GetClass() const + { + return wxT( "LIB_CIRCLE" ); + } + + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint& aPosRef, int aThreshold, const TRANSFORM& aTransform ) const; + + int GetPenSize( ) const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_Pos; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Width; } + + void SetWidth( int aWidth ) { m_Width = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_circle_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The circle specific sort order is as follows: + * - Circle horizontal (X) position. + * - Circle vertical (Y) position. + * - Circle radius. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_CIRCLE_H_ diff --git a/eeschema/lib_collectors.cpp b/eeschema/lib_collectors.cpp new file mode 100644 index 00000000..157c7abc --- /dev/null +++ b/eeschema/lib_collectors.cpp @@ -0,0 +1,131 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 +#include +#include +#include + + +const KICAD_T LIB_COLLECTOR::AllItems[] = { + LIB_ARC_T, + LIB_CIRCLE_T, + LIB_TEXT_T, + LIB_RECTANGLE_T, + LIB_POLYLINE_T, + LIB_BEZIER_T, + LIB_PIN_T, + LIB_FIELD_T, + EOT +}; + + +const KICAD_T LIB_COLLECTOR::AllItemsButPins[] = { + LIB_ARC_T, + LIB_CIRCLE_T, + LIB_TEXT_T, + LIB_RECTANGLE_T, + LIB_POLYLINE_T, + LIB_BEZIER_T, + LIB_FIELD_T, + EOT +}; + + +const KICAD_T LIB_COLLECTOR::EditableItems[] = { + LIB_ARC_T, + LIB_CIRCLE_T, + LIB_TEXT_T, + LIB_RECTANGLE_T, + LIB_POLYLINE_T, + LIB_BEZIER_T, + LIB_PIN_T, + LIB_FIELD_T, + EOT +}; + + +const KICAD_T LIB_COLLECTOR::MovableItems[] = { + LIB_ARC_T, + LIB_CIRCLE_T, + LIB_TEXT_T, + LIB_RECTANGLE_T, + LIB_POLYLINE_T, + LIB_BEZIER_T, + LIB_PIN_T, + LIB_FIELD_T, + EOT +}; + + +const KICAD_T LIB_COLLECTOR::RotatableItems[] = { + LIB_ARC_T, + LIB_CIRCLE_T, + LIB_TEXT_T, + LIB_RECTANGLE_T, + LIB_POLYLINE_T, + LIB_BEZIER_T, + LIB_PIN_T, + LIB_FIELD_T, + EOT +}; + + +SEARCH_RESULT LIB_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData ) +{ + LIB_ITEM* item = (LIB_ITEM*) aItem; + +// wxLogDebug( wxT( "Inspecting item %s, unit %d, convert %d" ), +// GetChars( item->GetSelectMenuText() ), item->GetUnit(), item->GetConvert() ); + + if( ( m_data.m_unit && item->GetUnit() && ( m_data.m_unit != item->GetUnit() ) ) + || ( m_data.m_convert && item->GetConvert() && ( m_data.m_convert != item->GetConvert() ) ) + || !item->HitTest( m_RefPos, -1, DefaultTransform ) ) + return SEARCH_CONTINUE; + + Append( aItem ); + + return SEARCH_CONTINUE; +} + + +void LIB_COLLECTOR::Collect( LIB_ITEMS& aItems, const KICAD_T aFilterList[], + const wxPoint& aPosition, int aUnit, int aConvert ) +{ + Empty(); // empty the collection just in case + + SetScanTypes( aFilterList ); + + // remember where the snapshot was taken from and pass refPos to the Inspect() function. + SetRefPos( aPosition ); + + m_data.m_unit = aUnit; + m_data.m_convert = aConvert; + + for( size_t i = 0; i < aItems.size(); i++ ) + { + if( SEARCH_QUIT == aItems[i].Visit( this, NULL, m_ScanTypes ) ) + break; + } +} diff --git a/eeschema/lib_collectors.h b/eeschema/lib_collectors.h new file mode 100644 index 00000000..e1b02a4a --- /dev/null +++ b/eeschema/lib_collectors.h @@ -0,0 +1,135 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2011 KiCad Developers, see change_log.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 _LIB_COLLECTORS_H_ +#define _LIB_COLLECTORS_H_ + + +#include +#include + + +class LIB_COLLECTOR; + + +class LIB_COLLECTOR_DATA +{ + int m_unit; + int m_convert; + + friend class LIB_COLLECTOR; + +public: + LIB_COLLECTOR_DATA() : + m_unit( 0 ), + m_convert( 0 ) {} +}; + + +/** + * Class LIB_COLLECTOR + */ +class LIB_COLLECTOR : public COLLECTOR +{ + LIB_COLLECTOR_DATA m_data; + +public: + + /** + * A scan list for all schematic items. + */ + static const KICAD_T AllItems[]; + + /** + * A scan list for all editable schematic items. + */ + static const KICAD_T EditableItems[]; + + /** + * A scan list for all movable schematic items. + */ + static const KICAD_T MovableItems[]; + + /** + * A scan list for all rotatable schematic items. + */ + static const KICAD_T RotatableItems[]; + + /** + * A scan list for all schematic items except pins. + */ + static const KICAD_T AllItemsButPins[]; + + /** + * Constructor LIB_COLLECTOR + */ + LIB_COLLECTOR( const KICAD_T* aScanTypes = LIB_COLLECTOR::AllItems ) + { + SetScanTypes( aScanTypes ); + } + + /** + * Operator [] + * overloads COLLECTOR::operator[](int) to return a LIB_ITEM* instead of + * an EDA_ITEM* type. + * @param aIndex The index into the list. + * @return LIB_ITEM* at \a aIndex or NULL. + */ + LIB_ITEM* operator[]( int aIndex ) const + { + if( (unsigned)aIndex < (unsigned)GetCount() ) + return (LIB_ITEM*) m_List[ aIndex ]; + + return NULL; + } + + /** + * Function Inspect + * is the examining function within the INSPECTOR which is passed to the + * Iterate function. + * + * @param aItem An EDA_ITEM to examine. + * @param aTestData is not used in this class. + * @return SEARCH_RESULT #SEARCH_QUIT if the iterator is to stop the scan, + * else #SEARCH_CONTINUE; + */ + SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL ); + + /** + * Function Collect + * scans a SCH_ITEM using this class's Inspector method, which does the collection. + * @param aItem A SCH_ITEM to scan. + * @param aFilterList A list of #KICAD_T types with a terminating #EOT, that determines + * what is to be collected and the priority order of the resulting + * collection. + * @param aPosition A wxPoint to use in hit-testing. + * @param aUnit The unit of the items to collect or zero if all units. + * @param aConvert The convert of the items to collect or zero if all conversions. + */ + void Collect( LIB_ITEMS& aItem, const KICAD_T aFilterList[], const wxPoint& aPosition, + int aUnit = 0, int aConvert = 0 ); +}; + + +#endif // _LIB_COLLECTORS_H_ diff --git a/eeschema/lib_draw_item.cpp b/eeschema/lib_draw_item.cpp new file mode 100644 index 00000000..4c05347c --- /dev/null +++ b/eeschema/lib_draw_item.cpp @@ -0,0 +1,160 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras at wanadoo.fr + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_draw_item.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include + +const int fill_tab[3] = { 'N', 'F', 'f' }; + +//#define DRAW_ARC_WITH_ANGLE // Used to draw arcs + + +LIB_ITEM::LIB_ITEM( KICAD_T aType, + LIB_PART* aComponent, + int aUnit, + int aConvert, + FILL_T aFillType ) : + EDA_ITEM( aType ) +{ + m_Unit = aUnit; + m_Convert = aConvert; + m_Fill = aFillType; + m_Parent = (EDA_ITEM*) aComponent; + m_typeName = _( "Undefined" ); + m_isFillable = false; + m_eraseLastDrawItem = false; +} + + +void LIB_ITEM::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + aList.push_back( MSG_PANEL_ITEM( _( "Type" ), m_typeName, CYAN ) ); + + if( m_Unit == 0 ) + msg = _( "All" ); + else + msg.Printf( wxT( "%d" ), m_Unit ); + + aList.push_back( MSG_PANEL_ITEM( _( "Unit" ), msg, BROWN ) ); + + if( m_Convert == 0 ) + msg = _( "All" ); + else if( m_Convert == 1 ) + msg = _( "no" ); + else if( m_Convert == 2 ) + msg = _( "yes" ); + else + msg = wxT( "?" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Convert" ), msg, BROWN ) ); +} + + +bool LIB_ITEM::operator==( const LIB_ITEM& aOther ) const +{ + return ( ( Type() == aOther.Type() ) + && ( m_Unit == aOther.m_Unit ) + && ( m_Convert == aOther.m_Convert ) + && compare( aOther ) == 0 ); +} + + +bool LIB_ITEM::operator<( const LIB_ITEM& aOther ) const +{ + int result = m_Convert - aOther.m_Convert; + + if( result != 0 ) + return result < 0; + + result = m_Unit - aOther.m_Unit; + + if( result != 0 ) + return result < 0; + + result = Type() - aOther.Type(); + + if( result != 0 ) + return result < 0; + + return ( compare( aOther ) < 0 ); +} + + +void LIB_ITEM::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, EDA_COLOR_T aColor, + GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + if( InEditMode() ) + { + // Temporarily disable filling while the item is being edited. + FILL_T fillMode = m_Fill; + EDA_COLOR_T color = GetDefaultColor(); + + m_Fill = NO_FILL; + +#ifndef USE_WX_OVERLAY + // Erase the old items using the previous attributes. + if( m_eraseLastDrawItem ) + { + GRSetDrawMode( aDC, g_XorMode ); + drawEditGraphics( aPanel->GetClipBox(), aDC, color ); + drawGraphic( aPanel, aDC, wxPoint( 0, 0 ), color, g_XorMode, aData, + aTransform ); + } +#endif + // Calculate the new attributes at the current cursor position. + calcEdit( aOffset ); + + // Draw the items using the new attributes. + drawEditGraphics( aPanel->GetClipBox(), aDC, color ); + drawGraphic( aPanel, aDC, wxPoint( 0, 0 ), color, g_XorMode, aData, + aTransform ); + + m_Fill = fillMode; + } + else + { + drawGraphic( aPanel, aDC, aOffset, aColor, aDrawMode, aData, aTransform ); + } +} + + +EDA_COLOR_T LIB_ITEM::GetDefaultColor() +{ + return GetLayerColor( LAYER_DEVICE ); +} diff --git a/eeschema/lib_draw_item.h b/eeschema/lib_draw_item.h new file mode 100644 index 00000000..47ca7a4e --- /dev/null +++ b/eeschema/lib_draw_item.h @@ -0,0 +1,448 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras at wanadoo.fr + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_libentry.h + * @brief Class LIB_ITEM definition. + */ + +#ifndef _LIB_ITEM_H_ +#define _LIB_ITEM_H_ + +#include +#include +#include + +#include + + +class LINE_READER; +class OUTPUTFORMATTER; +class LIB_PART; +class PLOTTER; +class LIB_ITEM; +class LIB_PIN; +class MSG_PANEL_ITEM; + + +extern const int fill_tab[]; + + +#define MINIMUM_SELECTION_DISTANCE 2 // Minimum selection distance in internal units + + +/** + * Helper for defining a list of library draw object pointers. The Boost + * pointer containers are responsible for deleting object pointers placed + * in them. If you access a object pointer from the list, do not delete + * it directly. + */ +typedef boost::ptr_vector< LIB_ITEM > LIB_ITEMS; + +/** + * Helper for defining a list of pin object pointers. The list does not + * use a Boost pointer class so the object pointers do not accidentally get + * deleted when the container is deleted. + */ +typedef std::vector< LIB_PIN* > LIB_PINS; + + +/** + * Class LIB_ITEM + * is the base class for drawable items used by schematic library components. + */ +class LIB_ITEM : public EDA_ITEM +{ + /** + * Function drawGraphic + * + * draws the item on \a aPanel. + * + * @param aPanel A pointer to the panel to draw the object upon. + * @param aDC A pointer to the device context used to draw the object. + * @param aOffset A reference to a wxPoint object containing the offset where to draw + * from the object's current position. + * @param aColor An #EDA_COLOR_T to draw the object or -1 to draw the object in it's + * default color. + * @param aDrawMode The mode used to perform the draw (#GR_OR, #GR_COPY, etc.). + * @param aData A pointer to any object specific data required to perform the draw. + * @param aTransform A reference to a #TRANSFORM object containing drawing transform. + */ + virtual void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, EDA_COLOR_T aColor, + GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) = 0; + + /** + * Draw any editing specific graphics when the item is being edited. + * + * @param aClipBox Clip box of the current device context. + * @param aDC The device context to draw on. + * @param aColor The index of the color to draw. + */ + virtual void drawEditGraphics( EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor ) {} + + /** + * Calculates the attributes of an item at \a aPosition when it is being edited. + * + * This method gets called by the Draw() method when the item is being edited. This + * probably should be a pure virtual method but bezier curves are not yet editable in + * the component library editor. Therefore, the default method does nothing. + * + * @param aPosition The current mouse position in drawing coordinates. + */ + virtual void calcEdit( const wxPoint& aPosition ) {} + + bool m_eraseLastDrawItem; ///< Used when editing a new draw item to prevent drawing + ///< artifacts. + + friend class LIB_PART; + +protected: + /** + * Unit identification for multiple parts per package. Set to 0 if the + * item is common to all units. + */ + int m_Unit; + + /** + * Shape identification for alternate body styles. Set 0 if the item + * is common to all body styles. This is commonly referred to as + * DeMorgan style and this is typically how it is used in KiCad. + */ + int m_Convert; + + /** + * The body fill type. This has meaning only for some items. For a list of + * fill types see #FILL_T. + */ + FILL_T m_Fill; + + wxString m_typeName; ///< Name of object displayed in the message panel. + + wxPoint m_initialPos; ///< Temporary position when moving an existing item. + wxPoint m_initialCursorPos; ///< Initial cursor position at the beginning of a move. + + /** Flag to indicate if draw item is fillable. Default is false. */ + bool m_isFillable; + +public: + + LIB_ITEM( KICAD_T aType, + LIB_PART* aComponent = NULL, + int aUnit = 0, + int aConvert = 0, + FILL_T aFillType = NO_FILL ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + virtual ~LIB_ITEM() { } + + wxString GetTypeName() { return m_typeName; } + + /** + * Begin an editing a component library draw item in \a aEditMode at \a aPosition. + * + * This is used to start an editing action such as resize or move a draw object. + * It typically would be called on a left click when a draw tool is selected in + * the component library editor and one of the graphics tools is selected. It + * allows the draw item to maintain it's own internal state while it is being + * edited. Call AbortEdit() to quit the editing mode. + * + * @param aEditMode The editing mode being performed. See base_struct.h for a list + * of mode flags. + * @param aPosition The position in drawing coordinates where the editing mode was + * started. This may or may not be required depending on the item + * being edited and the edit mode. + */ + virtual void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition = wxPoint( 0, 0 ) ) {} + + /** + * Continue an edit in progress at \a aPosition. + * + * This is used to perform the next action while editing a draw item. This would be + * called for each additional left click when the mouse is captured while the item + * is being edited. + * + * @param aPosition The position of the mouse left click in drawing coordinates. + * @return True if additional mouse clicks are required to complete the edit in progress. + */ + virtual bool ContinueEdit( const wxPoint aPosition ) { return false; } + + /** + * End an object editing action. + * + * This is used to end or abort an edit action in progress initiated by BeginEdit(). + * + * @param aPosition The position of the last edit event in drawing coordinates. + * @param aAbort Set to true to abort the current edit in progress. + */ + virtual void EndEdit( const wxPoint& aPosition, bool aAbort = false ) { m_Flags = 0; } + + /** + * Draw an item + * + * @param aPanel DrawPanel to use (can be null) mainly used for clipping purposes. + * @param aDC Device Context (can be null) + * @param aOffset Offset to draw + * @param aColor -1 to use the normal body item color, or use this color if >= 0 + * @param aDrawMode GR_OR, GR_XOR, ... + * @param aData Value or pointer used to pass others parameters, depending on body items. + * Used for some items to force to force no fill mode ( has meaning only for + * items what can be filled ). used in printing or moving objects mode or to + * pass reference to the lib component for pins. + * @param aTransform Transform Matrix (rotation, mirror ..) + */ + virtual void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint &aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + /** + * Function GetPenSize + * + * @return the size of the "pen" that be used to draw or plot this item + */ + virtual int GetPenSize() const = 0; + + /** + * Function Save + * writes draw item object to \a aFormatter in component library "*.lib" format. + * + * @param aFormatter A reference to an #OUTPUTFORMATTER object to write the + * component library item to. + * @return True if success writing else false. + */ + virtual bool Save( OUTPUTFORMATTER& aFormatter ) = 0; + + virtual bool Load( LINE_READER& aLine, wxString& aErrorMsg ) = 0; + + LIB_PART* GetParent() const + { + return (LIB_PART *)m_Parent; + } + + virtual bool HitTest( const wxPoint& aPosition ) const + { + return EDA_ITEM::HitTest( aPosition ); + } + + /** + * @param aPosition A wxPoint to test. + * @param aThreshold Maximum distance to this object (usually the half thickness of a line) + * if < 0, it will be automatically set to half pen size when locating + * lines or arcs and set to 0 for other items. + * @param aTransform The transform matrix. + * @return True if the point \a aPosition is near this object + */ + virtual bool HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const = 0; + + /** + * @return the boundary box for this, in library coordinates + */ + virtual const EDA_RECT GetBoundingBox() const { return EDA_ITEM::GetBoundingBox(); } + + /** + * Function GetMsgPanelInfo + * displays basic info (type, part and convert) about the current item + * in message panel. + *

      + * This base function is used to display the information common to the + * all library items. Call the base class from the derived class or the + * common information will not be updated in the message panel. + *

      + * @param aList is the list to populate. + */ + virtual void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + /** + * Test LIB_ITEM objects for equivalence. + * + * @param aOther Object to test against. + * @return True if object is identical to this object. + */ + bool operator==( const LIB_ITEM& aOther ) const; + bool operator==( const LIB_ITEM* aOther ) const + { + return *this == *aOther; + } + + /** + * Test if another draw item is less than this draw object. + * + * @param aOther - Draw item to compare against. + * @return - True if object is less than this object. + */ + bool operator<( const LIB_ITEM& aOther) const; + + /** + * Function Offset + * sets the drawing object by \a aOffset from the current position. + * + * @param aOffset Coordinates to offset the item position. + */ + virtual void SetOffset( const wxPoint& aOffset ) = 0; + + /** + * Function Inside + * tests if any part of the draw object is inside rectangle bounds of \a aRect. + * + * @param aRect Rectangle to check against. + * @return True if object is inside rectangle. + */ + virtual bool Inside( EDA_RECT& aRect ) const = 0; + + /** + * Function Move + * moves a draw object to \a aPosition. + * + * @param aPosition Position to move draw item to. + */ + virtual void Move( const wxPoint& aPosition ) = 0; + + /** + * Function GetPosition + * returns the current draw object position. + * + * @return A wxPoint object containing the position of the object. + */ + virtual wxPoint GetPosition() const = 0; + + void SetPosition( const wxPoint& aPosition ) { Move( aPosition ); } + + /** + * Function MirrorHorizontal + * mirrors the draw object along the horizontal (X) axis about \a aCenter point. + * + * @param aCenter Point to mirror around. + */ + virtual void MirrorHorizontal( const wxPoint& aCenter ) = 0; + + /** + * Function MirrorVertical + * mirrors the draw object along the MirrorVertical (Y) axis about \a aCenter point. + * + * @param aCenter Point to mirror around. + */ + virtual void MirrorVertical( const wxPoint& aCenter ) = 0; + + /** + * Function Rotate + * rotates the object about \a aCenter point. + * + * @param aCenter Point to rotate around. + * @param aRotateCCW True to rotate counter clockwise. False to rotate clockwise. + */ + virtual void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) = 0; + + /** + * Rotate the draw item. + */ + virtual void Rotate() {} + + /** + * Plot the draw item using the plot object. + * + * @param aPlotter The plot object to plot to. + * @param aOffset Plot offset position. + * @param aFill Flag to indicate whether or not the object is filled. + * @param aTransform The plot transform. + */ + virtual void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) = 0; + + /** + * Function GetWidth + * return the width of the draw item. + * + * @return Width of draw object. + */ + virtual int GetWidth() const = 0; + + /** + * Function SetWidth + * sets the width of the draw item to \a aWidth. + */ + virtual void SetWidth( int aWidth ) = 0; + + /** + * Check if draw object can be filled. + * + * The default setting is false. If the derived object support filling, + * set the m_isFillable member to true. + * + * @return True if draw object can be filled. Default is false. + */ + bool IsFillable() const { return m_isFillable; } + + /** + * Return the draw item editing mode status. + * + * @return True if the item is being edited. + */ + bool InEditMode() const { return ( m_Flags & ( IS_NEW | IS_DRAGGED | IS_MOVED | IS_RESIZED ) ) != 0; } + + void SetEraseLastDrawItem( bool aErase = true ) { m_eraseLastDrawItem = aErase; } + + virtual EDA_COLOR_T GetDefaultColor(); + + void SetUnit( int aUnit ) { m_Unit = aUnit; } + + int GetUnit() const { return m_Unit; } + + void SetConvert( int aConvert ) { m_Convert = aConvert; } + + int GetConvert() const { return m_Convert; } + + void SetFillMode( FILL_T aFillMode ) { m_Fill = aFillMode; } + + FILL_T GetFillMode() const { return m_Fill; } + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif + +private: + + /** + * Function compare + * provides the draw object specific comparison called by the == and < operators. + * + * The base object sort order which always proceeds the derived object sort order + * is as follows: + * - Component alternate part (DeMorgan) number. + * - Component part number. + * - KICAD_T enum value. + * - Result of derived classes comparison. + * + * @param aOther A reference to the other #LIB_ITEM to compare the arc against. + * @return An integer value less than 0 if the object is less than \a aOther ojbect, + * zero if the object is equal to \a aOther object, or greater than 0 if the + * object is greater than \a aOther object. + */ + virtual int compare( const LIB_ITEM& aOther ) const = 0; +}; + + +#endif // _LIB_ITEM_H_ diff --git a/eeschema/lib_export.cpp b/eeschema/lib_export.cpp new file mode 100644 index 00000000..ab74805d --- /dev/null +++ b/eeschema/lib_export.cpp @@ -0,0 +1,191 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2016 Wayne Stambaugh + * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_export.cpp + * @brief Eeschema library maintenance routines to backup modified libraries and + * create, edit, and delete components. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + + +extern int ExportPartId; + + +void LIB_EDIT_FRAME::OnImportPart( wxCommandEvent& event ) +{ + m_lastDrawItem = NULL; + + wxFileDialog dlg( this, _( "Import Component" ), m_mruPath, + wxEmptyString, SchematicLibraryFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + wxFileName fn = dlg.GetPath(); + + m_mruPath = fn.GetPath(); + + std::auto_ptr lib; + + try + { + std::auto_ptr new_lib( PART_LIB::LoadLibrary( fn.GetFullPath() ) ); + lib = new_lib; + } + catch( const IO_ERROR& ioe ) + { + wxString msg = wxString::Format( _( + "Unable to import library '%s'. Error:\n" + "%s" ), + GetChars( fn.GetFullPath() ) + ); + + DisplayError( this, msg ); + return; + } + + LIB_ALIAS* entry = lib->GetFirstEntry(); + + if( !entry ) + { + wxString msg = wxString::Format( _( + "Part library file '%s' is empty." ), + GetChars( fn.GetFullPath() ) + ); + DisplayError( this, msg ); + return; + } + + if( LoadOneLibraryPartAux( entry, lib.get() ) ) + { + DisplayLibInfos(); + GetScreen()->ClearUndoRedoList(); + Zoom_Automatique( false ); + } +} + + +void LIB_EDIT_FRAME::OnExportPart( wxCommandEvent& event ) +{ + wxString msg, title; + bool createLib = ( event.GetId() == ExportPartId ) ? false : true; + + LIB_PART* part = GetCurPart(); + + if( !part ) + { + DisplayError( this, _( "There is no component selected to save." ) ); + return; + } + + wxFileName fn = part->GetName().Lower(); + + fn.SetExt( SchematicLibraryFileExtension ); + + title = createLib ? _( "New Library" ) : _( "Export Component" ); + + wxFileDialog dlg( this, title, m_mruPath, fn.GetFullName(), + SchematicLibraryFileWildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + fn = dlg.GetPath(); + + std::auto_ptr temp_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) ); + + SaveOnePart( temp_lib.get() ); + + bool result = false; + + try + { + FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() ); + + result = temp_lib.get()->Save( formatter ); + } + catch( ... /* IO_ERROR ioe */ ) + { + fn.MakeAbsolute(); + msg = wxT( "Failed to create component library file " ) + fn.GetFullPath(); + DisplayError( this, msg ); + return; + } + + try + { + wxFileName docFileName = fn; + + docFileName.SetExt( DOC_EXT ); + + FILE_OUTPUTFORMATTER formatter( docFileName.GetFullPath() ); + + result = temp_lib.get()->SaveDocs( formatter ); + } + catch( ... /* IO_ERROR ioe */ ) + { + fn.MakeAbsolute(); + msg = wxT( "Failed to create component library document file " ) + fn.GetFullPath(); + DisplayError( this, msg ); + return; + } + + if( result ) + m_mruPath = fn.GetPath(); + + if( result ) + { + if( createLib ) + { + msg.Printf( _( "'%s' - OK" ), GetChars( fn.GetFullPath() ) ); + DisplayInfoMessage( this, _( + "This library will not be available until it is loaded by Eeschema.\n\n" + "Modify the Eeschema library configuration if you want to include it" + " as part of this project." ) ); + } + else + { + msg.Printf( _( "'%s' - Export OK" ), GetChars( fn.GetFullPath() ) ); + } + } + else // Error + { + msg.Printf( _( "Error creating '%s'" ), GetChars( fn.GetFullName() ) ); + } + + SetStatusText( msg ); +} diff --git a/eeschema/lib_field.cpp b/eeschema/lib_field.cpp new file mode 100644 index 00000000..5b6b01e6 --- /dev/null +++ b/eeschema/lib_field.cpp @@ -0,0 +1,771 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_field.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +LIB_FIELD::LIB_FIELD(LIB_PART * aParent, int idfield ) : + LIB_ITEM( LIB_FIELD_T, aParent ) +{ + Init( idfield ); +} + + +LIB_FIELD::LIB_FIELD( int idfield ) : LIB_ITEM( LIB_FIELD_T, NULL ) +{ + Init( idfield ); +} + + +LIB_FIELD::~LIB_FIELD() +{ +} + + +void LIB_FIELD::Init( int id ) +{ + m_id = id; + m_Size.x = GetDefaultTextSize(); + m_Size.y = GetDefaultTextSize(); + m_typeName = _( "Field" ); + m_Orient = TEXT_ORIENT_HORIZ; + m_rotate = false; + m_updateText = false; + + // fields in RAM must always have names, because we are trying to get + // less dependent on field ids and more dependent on names. + // Plus assumptions are made in the field editors. + m_name = TEMPLATE_FIELDNAME::GetDefaultFieldName( id ); + + switch( id ) + { + case DATASHEET: + case FOOTPRINT: + // by contrast, VALUE and REFERENCE are are always constructed as + // initially visible, and template fieldsnames' initial visibility + // is controlled by the template fieldname configuration record. + SetVisible( false ); + break; + } +} + + +bool LIB_FIELD::Save( OUTPUTFORMATTER& aFormatter ) +{ + int hjustify, vjustify; + wxString text = m_Text; + + hjustify = 'C'; + + if( m_HJustify == GR_TEXT_HJUSTIFY_LEFT ) + hjustify = 'L'; + else if( m_HJustify == GR_TEXT_HJUSTIFY_RIGHT ) + hjustify = 'R'; + + vjustify = 'C'; + + if( m_VJustify == GR_TEXT_VJUSTIFY_BOTTOM ) + vjustify = 'B'; + else if( m_VJustify == GR_TEXT_VJUSTIFY_TOP ) + vjustify = 'T'; + + aFormatter.Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c", + m_id, + EscapedUTF8( text ).c_str(), // wraps in quotes + m_Pos.x, m_Pos.y, m_Size.x, + m_Orient == 0 ? 'H' : 'V', + (m_Attributs & TEXT_NO_VISIBLE ) ? 'I' : 'V', + hjustify, vjustify, + m_Italic ? 'I' : 'N', + m_Bold ? 'B' : 'N' ); + + /* Save field name, if necessary + * Field name is saved only if it is not the default name. + * Just because default name depends on the language and can change from + * a country to an other + */ + wxString defName = TEMPLATE_FIELDNAME::GetDefaultFieldName( m_id ); + + if( m_id >= FIELD1 && !m_name.IsEmpty() && m_name != defName ) + aFormatter.Print( 0, " %s", EscapedUTF8( m_name ).c_str() ); + + aFormatter.Print( 0, "\n" ); + + return true; +} + + +bool LIB_FIELD::Load( LINE_READER& aLineReader, wxString& errorMsg ) +{ + int cnt; + char textOrient; + char textVisible; + char textHJustify; + char textVJustify[256]; + + char* line = (char*) aLineReader; + char* limit = line + aLineReader.Length(); + + if( sscanf( line + 1, "%d", &m_id ) != 1 || m_id < 0 ) + { + errorMsg = wxT( "invalid field header" ); + return false; + } + + // Caller did a strtok(), which inserts a nul, so next few bytes are ugly: + // digit(s), a nul, some whitespace, then a double quote. + while( line < limit && *line != '"' ) + line++; + + if( line == limit ) + return false; + + line += ReadDelimitedText( &m_Text, line ); + + // Doctor the *.lib file field which has a "~" in blank fields. New saves will + // not save like this, and eventually these two lines can be removed. + if( m_Text.size() == 1 && m_Text[0] == wxChar( '~' ) ) + m_Text.clear(); + + memset( textVJustify, 0, sizeof( textVJustify ) ); + + cnt = sscanf( line, " %d %d %d %c %c %c %255s", &m_Pos.x, &m_Pos.y, &m_Size.y, + &textOrient, &textVisible, &textHJustify, textVJustify ); + + if( cnt < 5 ) + { + errorMsg.Printf( wxT( "field %d does not have the correct number of parameters" ), + m_id ); + return false; + } + + m_Size.x = m_Size.y; + + if( textOrient == 'H' ) + m_Orient = TEXT_ORIENT_HORIZ; + else if( textOrient == 'V' ) + m_Orient = TEXT_ORIENT_VERT; + else + { + errorMsg.Printf( wxT( "field %d text orientation parameter <%c> is not valid" ), + textOrient ); + return false; + } + + if( textVisible == 'V' ) + m_Attributs &= ~TEXT_NO_VISIBLE; + else if ( textVisible == 'I' ) + m_Attributs |= TEXT_NO_VISIBLE; + else + { + errorMsg.Printf( wxT( "field %d text visible parameter <%c> is not valid" ), + textVisible ); + return false; + } + + m_HJustify = GR_TEXT_HJUSTIFY_CENTER; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + + if( cnt >= 6 ) + { + if( textHJustify == 'C' ) + m_HJustify = GR_TEXT_HJUSTIFY_CENTER; + else if( textHJustify == 'L' ) + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + else if( textHJustify == 'R' ) + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + else + { + errorMsg.Printf( + wxT( "field %d text horizontal justification parameter <%c> is not valid" ), + textHJustify ); + return false; + } + + if( textVJustify[0] == 'C' ) + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + else if( textVJustify[0] == 'B' ) + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + else if( textVJustify[0] == 'T' ) + m_VJustify = GR_TEXT_VJUSTIFY_TOP; + else + { + errorMsg.Printf( + wxT( "field %d text vertical justification parameter <%c> is not valid" ), + textVJustify[0] ); + return false; + } + + if ( textVJustify[1] == 'I' ) // Italic + m_Italic = true; + if ( textVJustify[2] == 'B' ) // Bold + m_Bold = true; + } + + // fields in RAM must always have names. + if( m_id < MANDATORY_FIELDS ) + { + // Fields in RAM must always have names, because we are trying to get + // less dependent on field ids and more dependent on names. + // Plus assumptions are made in the field editors. + m_name = TEMPLATE_FIELDNAME::GetDefaultFieldName( m_id ); + } + else + { + ReadDelimitedText( &m_name, line ); + } + + return true; +} + + +int LIB_FIELD::GetPenSize() const +{ + return ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; +} + + +void LIB_FIELD::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + wxPoint text_pos; + int color; + int linewidth = GetPenSize(); + + if( m_Bold ) + linewidth = GetPenSizeForBold( m_Size.x ); + else + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + if( ( m_Attributs & TEXT_NO_VISIBLE ) && ( aColor < 0 ) ) + { + color = GetInvisibleItemColor(); + } + else if( IsSelected() && ( aColor < 0 ) ) + { + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + if( color < 0 ) + color = GetDefaultColor(); + + text_pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; + + wxString text; + + if( aData ) + text = *(wxString*)aData; + else + text = m_Text; + + GRSetDrawMode( aDC, aDrawMode ); + EDA_RECT* clipbox = aPanel? aPanel->GetClipBox() : NULL; + DrawGraphicText( clipbox, aDC, text_pos, (EDA_COLOR_T) color, text, m_Orient, m_Size, + m_HJustify, m_VJustify, linewidth, m_Italic, m_Bold ); + + /* Set to one (1) to draw bounding box around field text to validate + * bounding box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +bool LIB_FIELD::HitTest( const wxPoint& aPosition ) const +{ + // Because HitTest is mainly used to select the field + // return always false if this field is void + if( IsVoid() ) + return false; + + return HitTest( aPosition, 0, DefaultTransform ); +} + + +bool LIB_FIELD::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + if( aThreshold < 0 ) + aThreshold = 0; + + // Build a temporary copy of the text for hit testing + EDA_TEXT tmp_text( *this ); + + // Reference designator text has one or 2 additional character (displays + // U? or U?A) + if( m_id == REFERENCE ) + { + wxString extended_text = tmp_text.GetText(); + extended_text.Append('?'); + const LIB_PART* parent = static_cast( m_Parent ); + + if ( parent && ( parent->GetUnitCount() > 1 ) ) + extended_text.Append('A'); + tmp_text.SetText( extended_text ); + } + + tmp_text.SetTextPosition( aTransform.TransformCoordinate( m_Pos ) ); + + /* The text orientation may need to be flipped if the + * transformation matrix causes xy axes to be flipped. + * this simple algo works only for schematic matrix (rot 90 or/and mirror) + */ + int t1 = ( aTransform.x1 != 0 ) ^ ( m_Orient != 0 ); + tmp_text.SetOrientation( t1 ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT ); + + return tmp_text.TextHitTest( aPosition ); +} + + +EDA_ITEM* LIB_FIELD::Clone() const +{ + LIB_FIELD* newfield = new LIB_FIELD( m_id ); + + Copy( newfield ); + + return (EDA_ITEM*) newfield; +} + + +void LIB_FIELD::Copy( LIB_FIELD* aTarget ) const +{ + aTarget->SetParent( m_Parent ); + aTarget->m_Pos = m_Pos; + aTarget->m_Size = m_Size; + aTarget->m_Thickness = m_Thickness; + aTarget->m_Orient = m_Orient; + aTarget->m_Attributs = m_Attributs; + aTarget->m_Text = m_Text; + aTarget->m_name = m_name; + aTarget->m_HJustify = m_HJustify; + aTarget->m_VJustify = m_VJustify; + aTarget->m_Italic = m_Italic; + aTarget->m_Bold = m_Bold; +} + + +int LIB_FIELD::compare( const LIB_ITEM& other ) const +{ + wxASSERT( other.Type() == LIB_FIELD_T ); + + const LIB_FIELD* tmp = ( LIB_FIELD* ) &other; + + if( m_id != tmp->m_id ) + return m_id - tmp->m_id; + + int result = m_Text.CmpNoCase( tmp->m_Text ); + + if( result != 0 ) + return result; + + if( m_Pos.x != tmp->m_Pos.x ) + return m_Pos.x - tmp->m_Pos.x; + + if( m_Pos.y != tmp->m_Pos.y ) + return m_Pos.y - tmp->m_Pos.y; + + if( m_Size.x != tmp->m_Size.x ) + return m_Size.x - tmp->m_Size.x; + + if( m_Size.y != tmp->m_Size.y ) + return m_Size.y - tmp->m_Size.y; + + return 0; +} + + +void LIB_FIELD::SetOffset( const wxPoint& aOffset ) +{ + m_Pos += aOffset; +} + + +bool LIB_FIELD::Inside( EDA_RECT& rect ) const +{ + /* + * FIXME: This fails to take into account the size and/or orientation of + * the text. + */ + return rect.Contains( m_Pos.x, -m_Pos.y ); +} + + +void LIB_FIELD::Move( const wxPoint& newPosition ) +{ + m_Pos = newPosition; +} + + +void LIB_FIELD::MirrorHorizontal( const wxPoint& center ) +{ + m_Pos.x -= center.x; + m_Pos.x *= -1; + m_Pos.x += center.x; +} + +void LIB_FIELD::MirrorVertical( const wxPoint& center ) +{ + m_Pos.y -= center.y; + m_Pos.y *= -1; + m_Pos.y += center.y; +} + +void LIB_FIELD::Rotate( const wxPoint& center, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + RotatePoint( &m_Pos, center, rot_angle ); + m_Orient = m_Orient ? 0 : 900; +} + + +void LIB_FIELD::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + if( IsVoid() ) + return; + + /* Calculate the text orientation, according to the component + * orientation/mirror */ + int orient = m_Orient; + + if( aTransform.y1 ) // Rotate component 90 deg. + { + if( orient == TEXT_ORIENT_HORIZ ) + orient = TEXT_ORIENT_VERT; + else + orient = TEXT_ORIENT_HORIZ; + } + + EDA_RECT BoundaryBox = GetBoundingBox(); + BoundaryBox.RevertYAxis(); + + EDA_TEXT_HJUSTIFY_T hjustify = GR_TEXT_HJUSTIFY_CENTER; + EDA_TEXT_VJUSTIFY_T vjustify = GR_TEXT_VJUSTIFY_CENTER; + wxPoint textpos = aTransform.TransformCoordinate( BoundaryBox.Centre() ) + + aOffset; + + aPlotter->Text( textpos, GetDefaultColor(), GetShownText(), orient, m_Size, + hjustify, vjustify, + GetPenSize(), m_Italic, m_Bold ); +} + + +wxString LIB_FIELD::GetFullText( int unit ) +{ + if( m_id != REFERENCE ) + return GetText(); + + wxString text = GetText(); + text << wxT( "?" ); + + if( GetParent()->IsMulti() ) + text << LIB_PART::SubReference( unit ); + + return text; +} + + +const EDA_RECT LIB_FIELD::GetBoundingBox() const +{ + /* Y coordinates for LIB_ITEMS are bottom to top, so we must invert the Y position when + * calling GetTextBox() that works using top to bottom Y axis orientation. + */ + EDA_RECT rect = GetTextBox( -1, -1, true ); + rect.RevertYAxis(); + + // We are using now a bottom to top Y axis. + wxPoint orig = rect.GetOrigin(); + wxPoint end = rect.GetEnd(); + RotatePoint( &orig, m_Pos, -m_Orient ); + RotatePoint( &end, m_Pos, -m_Orient ); + rect.SetOrigin( orig ); + rect.SetEnd( end ); + + // We are using now a top to bottom Y axis: + rect.RevertYAxis(); + + return rect; +} + + +EDA_COLOR_T LIB_FIELD::GetDefaultColor() +{ + EDA_COLOR_T color; + + switch( m_id ) + { + case REFERENCE: + color = GetLayerColor( LAYER_REFERENCEPART ); + break; + + case VALUE: + color = GetLayerColor( LAYER_VALUEPART ); + break; + + default: + color = GetLayerColor( LAYER_FIELDS ); + break; + } + + return color; +} + + +void LIB_FIELD::Rotate() +{ + if( InEditMode() ) + { + m_rotate = true; + } + else + { + m_Orient = ( m_Orient == TEXT_ORIENT_VERT ) ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT; + } +} + + +wxString LIB_FIELD::GetName( bool aTranslate ) const +{ + wxString name; + + switch( m_id ) + { + case REFERENCE: + if( aTranslate ) + name = _( "Reference" ); + else + name = wxT( "Reference" ); + break; + + case VALUE: + if( aTranslate ) + name = _( "Value" ); + else + name = wxT( "Value" ); + break; + + case FOOTPRINT: + if( aTranslate ) + name = _( "Footprint" ); + else + name = wxT( "Footprint" ); + break; + + case DATASHEET: + if( aTranslate ) + name = _( "Datasheet" ); + else + name = wxT( "Datasheet" ); + break; + + default: + if( m_name.IsEmpty() ) + { + if( aTranslate ) + name.Printf( _( "Field%d" ), m_id ); + else + name.Printf( wxT( "Field%d" ), m_id ); + } + else + name = m_name; + } + + return name; +} + + +void LIB_FIELD::SetName( const wxString& aName ) +{ + // Mandatory field names are fixed. + + // So what? Why should the low level code be in charge of such a policy issue? + // Besides, m_id is a relic that is untrustworthy now. + if( m_id >=0 && m_id < MANDATORY_FIELDS ) + { + DBG(printf( "trying to set a MANDATORY_FIELD's name\n" );) + return; + } + + if( m_name != aName ) + { + m_name = aName; + SetModified(); + } +} + + +void LIB_FIELD::SetText( const wxString& aText ) +{ + if( aText == GetText() ) + return; + + wxString oldName = m_Text; + + if( m_id == VALUE && m_Parent != NULL ) + { + LIB_PART* parent = GetParent(); + + // Set the parent component and root alias to the new name. + if( parent->GetName().CmpNoCase( aText ) != 0 ) + parent->SetName( aText ); + } + + if( InEditMode() ) + { + m_Text = oldName; + m_savedText = aText; + m_updateText = true; + } + else + { + m_Text = aText; + } +} + + +wxString LIB_FIELD::GetSelectMenuText() const +{ + return wxString::Format( _( "Field %s %s" ), + GetChars( GetName() ), + GetChars( ShortenedShownText() ) ); +} + + +void LIB_FIELD::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED ) ) != 0, + wxT( "Invalid edit mode for LIB_FIELD object." ) ); + + if( aEditMode == IS_MOVED ) + { + m_initialPos = m_Pos; + m_initialCursorPos = aPosition; + SetEraseLastDrawItem(); + } + else + { + m_Pos = aPosition; + } + + m_Flags = aEditMode; +} + + +bool LIB_FIELD::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). Text is not being edited." ) ); + + return false; +} + + +void LIB_FIELD::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED ) ) != 0, + wxT( "Bad call to EndEdit(). Text is not being edited." ) ); + + m_Flags = 0; + m_rotate = false; + m_updateText = false; + SetEraseLastDrawItem( false ); +} + + +void LIB_FIELD::calcEdit( const wxPoint& aPosition ) +{ + if( m_rotate ) + { + m_Orient = ( m_Orient == TEXT_ORIENT_VERT ) ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT; + m_rotate = false; + } + + if( m_updateText ) + { + std::swap( m_Text, m_savedText ); + m_updateText = false; + } + + if( m_Flags == IS_NEW ) + { + m_Pos = aPosition; + } + else if( m_Flags == IS_MOVED ) + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} + +void LIB_FIELD::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + LIB_ITEM::GetMsgPanelInfo( aList ); + + // Display style: + msg = GetTextStyleName(); + aList.push_back( MSG_PANEL_ITEM( _( "Style" ), msg, MAGENTA ) ); + + msg = StringFromValue( g_UserUnit, m_Size.x, true ); + aList.push_back( MSG_PANEL_ITEM( _( "Width" ), msg, BLUE ) ); + + msg = StringFromValue( g_UserUnit, m_Size.y, true ); + aList.push_back( MSG_PANEL_ITEM( _( "Height" ), msg, BLUE ) ); + + // Display field name (ref, value ...) + msg = GetName(); + aList.push_back( MSG_PANEL_ITEM( _( "Field" ), msg, BROWN ) ); + + // Display field text: + aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetShownText(), BROWN ) ); +} diff --git a/eeschema/lib_field.h b/eeschema/lib_field.h new file mode 100644 index 00000000..1f8f8e7e --- /dev/null +++ b/eeschema/lib_field.h @@ -0,0 +1,277 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_field.h + */ + +#ifndef CLASS_LIBENTRY_FIELDS_H +#define CLASS_LIBENTRY_FIELDS_H + +#include +#include + + +/** + * Class LIB_FIELD + * is used in symbol libraries. At least MANDATORY_FIELDS are always present + * in a ram resident library symbol. All constructors must ensure this because + * the component property editor assumes it. + *

      + * A field is a string linked to a component. Unlike purely graphical text, fields can + * be used in netlist generation and other tools (BOM). + * + * The first 4 fields have a special meaning: + * + * 0 = REFERENCE + * 1 = VALUE + * 2 = FOOTPRINT (default Footprint) + * 3 = DATASHEET (user doc link) + * + * others = free fields + *

      + * + * @see enum NumFieldType + */ +class LIB_FIELD : public LIB_ITEM, public EDA_TEXT +{ + int m_id; ///< @see enum NumFieldType + wxString m_name; ///< Name (not the field text value itself, that is .m_Text) + + wxString m_savedText; ///< Temporary storage for the string when edition. + bool m_rotate; ///< Flag to indicate a rotation occurred while editing. + bool m_updateText; ///< Flag to indicate text change occurred while editing. + + /** + * Draw the field. + *

      + * If \a aData not NULL, \a aData must point a wxString which is used instead of + * the m_Text + *

      + */ + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + /** + * Calculate the new circle at \a aPosition when editing. + * + * @param aPosition - The position to edit the circle in drawing coordinates. + */ + void calcEdit( const wxPoint& aPosition ); + +public: + + LIB_FIELD( int idfield = 2 ); + + LIB_FIELD( LIB_PART * aParent, int idfield = 2 ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_FIELD(); + + wxString GetClass() const + { + return wxT( "LIB_FIELD" ); + } + + /** + * Object constructor initialization helper. + */ + void Init( int idfield ); + + /** + * Returns the field name. + * + * The first four field IDs are reserved and therefore always return their respective + * names. The user definable fields will return FieldN where N is the ID of the field + * when the m_name member is empty. + * + * @param aTranslate True to return translated field name (default). False to return + * the english name (useful when the name is used as keyword in + * netlists ...) + * @return Name of the field. + */ + wxString GetName( bool aTranslate = true ) const; + + /** + * Function SetName + * + * Sets a user definable field name to \a aName. + * + * Reserved fields such as value and reference are not renamed. If the field name is + * changed, the field modified flag is set. If the field is the child of a component, + * the parent component's modified flag is also set. + * + * @param aName - User defined field name. + */ + void SetName( const wxString& aName ); + + int GetId() const { return m_id; } + + void SetId( int aId ) { m_id = aId; } + + int GetPenSize( ) const; + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& errorMsg ); + + /** + * Copy parameters of this field to another field. Pointers are not copied. + * + * @param aTarget Target field to copy values to. + */ + void Copy( LIB_FIELD* aTarget ) const; + + void SetFields( const std::vector aFields ); + + /** + * Function IsVoid + * @return true if the field value is void (no text in this field) + */ + bool IsVoid() const + { + return m_Text.IsEmpty(); + } + + /** + * Function IsVisible + * @return true is this field is visible, false if flagged invisible + */ + bool IsVisible() + { + return (m_Attributs & TEXT_NO_VISIBLE) == 0 ? true : false; + } + + const EDA_RECT GetBoundingBox() const; // Virtual + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const; + + void operator=( const LIB_FIELD& field ) + { + m_id = field.m_id; + m_Text = field.m_Text; + m_name = field.m_name; + m_Pos = field.m_Pos; + m_Size = field.m_Size; + m_Thickness = field.m_Thickness; + m_Orient = field.m_Orient; + m_Mirror = field.m_Mirror; + m_Attributs = field.m_Attributs; + m_Italic = field.m_Italic; + m_Bold = field.m_Bold; + m_HJustify = field.m_HJustify; + m_VJustify = field.m_VJustify; + m_Parent = field.m_Parent; + } + + /** + * Return the text of a field. + * + * If the field is the reference field, the unit number is used to + * create a pseudo reference text. If the base reference field is U, + * the string U?A will be returned for unit = 1. + * + * @todo This should be handled by the field object. + * + * @param unit - The package unit number. Only effects reference field. + * @return Field text. + */ + wxString GetFullText( int unit = 1 ); + + EDA_COLOR_T GetDefaultColor(); + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void Rotate(); + + /** + * Sets the field text to \a aText. + * + * This method does more than just set the set the field text. There are special + * cases when changing the text string alone is not enough. If the field is the + * value field, the parent component's name is changed as well. If the field is + * being moved, the name change must be delayed until the next redraw to prevent + * drawing artifacts. + * + * @param aText - New text value. + */ + void SetText( const wxString& aText ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_Pos; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Thickness; } + + void SetWidth( int aWidth ) { m_Thickness = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return move_field_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The field specific sort order is as follows: + * + * - Field ID, REFERENCE, VALUE, etc. + * - Field string, case insensitive compare. + * - Field horizontal (X) position. + * - Field vertical (Y) position. + * - Field width. + * - Field height. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + +typedef std::vector< LIB_FIELD > LIB_FIELDS; + +#endif // CLASS_LIBENTRY_FIELDS_H diff --git a/eeschema/lib_pin.cpp b/eeschema/lib_pin.cpp new file mode 100644 index 00000000..e4b221f3 --- /dev/null +++ b/eeschema/lib_pin.cpp @@ -0,0 +1,2314 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file lib_pin.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +static const int pin_orientation_codes[] = +{ + PIN_RIGHT, + PIN_LEFT, + PIN_UP, + PIN_DOWN +}; + + +#define PIN_ORIENTATION_CNT DIM( pin_orientation_codes ) + +// bitmaps to show pins orientations in dialog editor +// must have same order than pin_orientation_names +static const BITMAP_DEF iconsPinsOrientations[] = +{ + pinorient_right_xpm, + pinorient_left_xpm, + pinorient_up_xpm, + pinorient_down_xpm, +}; + + +// bitmaps to show pins shapes in dialog editor +// must have same order than pin_style_names +static BITMAP_DEF iconsPinsShapes[] = +{ + pinshape_normal_xpm, + pinshape_invert_xpm, + pinshape_clock_normal_xpm, + pinshape_clock_invert_xpm, + pinshape_active_low_input_xpm, + pinshape_clock_active_low_xpm, + pinshape_active_low_output_xpm, + pinshape_clock_fall_xpm, + pinshape_nonlogic_xpm +}; + + + +static const int pin_style_codes[] = +{ + NONE, + INVERT, + CLOCK, + CLOCK | INVERT, + LOWLEVEL_IN, + LOWLEVEL_IN | CLOCK, + LOWLEVEL_OUT, + CLOCK_FALL, + NONLOGIC +}; + +#define PIN_STYLE_CNT DIM( pin_style_codes ) + +// bitmaps to show pins electrical type in dialog editor +// must have same order than enum ElectricPinType (see lib_pin.h) +static const BITMAP_DEF iconsPinsElectricalType[] = +{ + pintype_input_xpm, + pintype_output_xpm, + pintype_bidi_xpm, + pintype_3states_xpm, + pintype_passive_xpm, + pintype_notspecif_xpm, + pintype_powerinput_xpm, + pintype_poweroutput_xpm, + pintype_opencoll_xpm, + pintype_openemit_xpm, + pintype_noconnect_xpm +}; + +#define PIN_ELECTRICAL_TYPE_CNT DIM( iconsPinsElectricalType ) + + +const wxString LIB_PIN::GetCanonicalElectricalTypeName( unsigned aType ) +{ + // These strings are the canonical name of the electrictal type + // Not translated, no space in name, only ASCII chars. + // to use when the string name must be known and well defined + // must have same order than enum ElectricPinType (see lib_pin.h) + static const wxChar* msgPinElectricType[] = + { + wxT( "input" ), + wxT( "output" ), + wxT( "BiDi" ), + wxT( "3state" ), + wxT( "passive" ), + wxT( "unspc" ), + wxT( "power_in" ), + wxT( "power_out" ), + wxT( "openCol" ), + wxT( "openEm" ), + wxT( "NotConnected" ), + wxT( "???" ) + }; + + if( aType > PIN_NMAX ) + aType = PIN_NMAX; + + return msgPinElectricType[ aType ]; +} + + +// Helper functions to get the pin orientation name from pin_orientation_codes +// Note: the strings are *not* static because they are translated and must be built +// on the fly, to be properly translated + +static const wxString getPinOrientationName( unsigned aPinOrientationCode ) +{ + /* Note: The following name lists are sentence capitalized per the GNOME UI + * standards for list controls. Please do not change the capitalization + * of these strings unless the GNOME UI standards are changed. + */ + const wxString pin_orientation_names[] = + { + _( "Right" ), + _( "Left" ), + _( "Up" ), + _( "Down" ), + wxT( "???" ) + }; + + if( aPinOrientationCode > PIN_ORIENTATION_CNT ) + aPinOrientationCode = PIN_ORIENTATION_CNT; + + return pin_orientation_names[ aPinOrientationCode ]; +} + +const wxString LIB_PIN::GetElectricalTypeName( unsigned aPinsElectricalType ) +{ + const wxString pin_electrical_type_names[] = + { // Keep these translated strings not static + _( "Input" ), + _( "Output" ), + _( "Bidirectional" ), + _( "Tri-state" ), + _( "Passive" ), + _( "Unspecified" ), + _( "Power input" ), + _( "Power output" ), + _( "Open collector" ), + _( "Open emitter" ), + _( "Not connected" ), + wxT( "???" ) + }; + + if( aPinsElectricalType > PIN_ELECTRICAL_TYPE_CNT ) + aPinsElectricalType = PIN_ELECTRICAL_TYPE_CNT; + + return pin_electrical_type_names[ aPinsElectricalType ]; +} + +static const wxString getPinStyleName( unsigned aPinsStyle ) +{ + const wxString pin_style_names[] = + { // Keep these translated strings not static + _( "Line" ), + _( "Inverted" ), + _( "Clock" ), + _( "Inverted clock" ), + _( "Input low" ), + _( "Clock low" ), + _( "Output low" ), + _( "Falling edge clock" ), + _( "NonLogic" ), + wxT( "???" ) + }; + + if( aPinsStyle > PIN_STYLE_CNT ) + aPinsStyle = PIN_STYLE_CNT; + + return pin_style_names[ aPinsStyle ]; +} + + +/// Utility for getting the size of the 'internal' pin decorators (as a radius) +// i.e. the clock symbols (falling clock is actually external but is of +// the same kind) + +static int InternalPinDecoSize( const LIB_PIN &aPin ) +{ + return aPin.GetNameTextSize() / 2; +} + +/// Utility for getting the size of the 'external' pin decorators (as a radius) +// i.e. the negation circle, the polarity 'slopes' and the nonlogic +// marker +static int ExternalPinDecoSize( const LIB_PIN &aPin ) +{ + return aPin.GetNumberTextSize() / 2; +} + +LIB_PIN::LIB_PIN( LIB_PART* aParent ) : + LIB_ITEM( LIB_PIN_T, aParent ) +{ + m_length = LIB_EDIT_FRAME::GetDefaultPinLength(); + m_orientation = PIN_RIGHT; // Pin orient: Up, Down, Left, Right + m_shape = NONE; // Pin shape, bitwise. + m_type = PIN_UNSPECIFIED; // electrical type of pin + m_attributes = 0; // bit 0 != 0: pin invisible + m_number = 0; // pin number (i.e. 4 ASCII chars) + m_numTextSize = LIB_EDIT_FRAME::GetPinNumDefaultSize(); + m_nameTextSize = LIB_EDIT_FRAME::GetPinNameDefaultSize(); + m_width = 0; + m_typeName = _( "Pin" ); +} + + +void LIB_PIN::SetName( const wxString& aName ) +{ + wxString tmp = ( aName.IsEmpty() ) ? wxT( "~" ) : aName; + + tmp.Replace( wxT( " " ), wxT( "_" ) ); + + if( m_name != tmp ) + { + m_name = tmp; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || pinList[i]->m_name == m_name ) + continue; + + pinList[i]->m_name = m_name; + SetModified(); + } +} + + +void LIB_PIN::SetNameTextSize( int size ) +{ + if( size != m_nameTextSize ) + { + m_nameTextSize = size; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || pinList[i]->m_nameTextSize == size ) + continue; + + pinList[i]->m_nameTextSize = size; + SetModified(); + } +} + + +void LIB_PIN::SetNumber( const wxString& number ) +{ + wxString tmp = ( number.IsEmpty() ) ? wxT( "~" ) : number; + + tmp.Replace( wxT( " " ), wxT( "_" ) ); + long oldNumber = m_number; + SetPinNumFromString( tmp ); + + if( m_number != oldNumber ) + SetFlags( IS_CHANGED ); + + /* Others pin numbers marked by EnableEditMode() are not modified + * because each pin has its own number + */ +} + + +void LIB_PIN::SetNumberTextSize( int size ) +{ + if( size != m_numTextSize ) + { + m_numTextSize = size; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || pinList[i]->m_numTextSize == size ) + continue; + + pinList[i]->m_numTextSize = size; + SetModified(); + } +} + + +void LIB_PIN::SetOrientation( int orientation ) +{ + if( m_orientation != orientation ) + { + m_orientation = orientation; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || + pinList[i]->m_orientation == orientation ) + continue; + + pinList[i]->m_orientation = orientation; + SetModified(); + } +} + + +void LIB_PIN::SetShape( int aShape ) +{ + if( m_shape != aShape ) + { + m_shape = aShape; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 + || pinList[i]->m_Convert != m_Convert + || pinList[i]->m_shape == aShape ) + continue; + + pinList[i]->m_shape = aShape; + SetModified(); + } +} + + +void LIB_PIN::SetType( int aType ) +{ + if( aType < 0 ) + aType = 0; + + if( aType >= (int)PIN_ELECTRICAL_TYPE_CNT ) + aType = PIN_ELECTRICAL_TYPE_CNT - 1; + + if( m_type != aType ) + { + m_type = aType; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || pinList[i]->m_type == aType ) + continue; + + pinList[i]->m_type = aType; + SetModified(); + } +} + + +void LIB_PIN::SetLength( int length ) +{ + if( m_length != length ) + { + m_length = length; + SetModified(); + } + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 + || pinList[i]->m_Convert != m_Convert + || pinList[i]->m_length == length ) + continue; + + pinList[i]->m_length = length; + SetModified(); + } +} + + +void LIB_PIN::SetPartNumber( int part ) +{ + if( m_Unit == part ) + return; + + m_Unit = part; + SetModified(); + + if( m_Unit == 0 ) + { + LIB_PIN* pin; + LIB_PIN* tmp = GetParent()->GetNextPin(); + + while( tmp != NULL ) + { + pin = tmp; + tmp = GetParent()->GetNextPin( pin ); + + if( pin->m_Flags == 0 || pin == this + || ( m_Convert && ( m_Convert != pin->m_Convert ) ) + || ( m_position != pin->m_position ) + || ( pin->m_orientation != m_orientation ) ) + continue; + + GetParent()->RemoveDrawItem( (LIB_ITEM*) pin ); + } + } +} + + +void LIB_PIN::SetConversion( int style ) +{ + if( m_Convert == style ) + return; + + m_Convert = style; + SetFlags( IS_CHANGED ); + + if( style == 0 ) + { + LIB_PIN* pin; + LIB_PIN* tmp = GetParent()->GetNextPin(); + + while( tmp != NULL ) + { + pin = tmp; + tmp = GetParent()->GetNextPin( pin ); + + if( ( pin->m_Flags & IS_LINKED ) == 0 + || ( pin == this ) + || ( m_Unit && ( m_Unit != pin->m_Unit ) ) + || ( m_position != pin->m_position ) + || ( pin->m_orientation != m_orientation ) ) + continue; + + GetParent()->RemoveDrawItem( (LIB_ITEM*) pin ); + } + } +} + + +void LIB_PIN::SetVisible( bool visible ) +{ + if( visible == IsVisible() ) + return; + + if( visible ) + m_attributes &= ~PIN_INVISIBLE; + else + m_attributes |= PIN_INVISIBLE; + + SetModified(); + + if( GetParent() == NULL ) + return; + + LIB_PINS pinList; + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( ( pinList[i]->m_Flags & IS_LINKED ) == 0 || pinList[i]->IsVisible() == visible ) + continue; + + if( visible ) + pinList[i]->m_attributes &= ~PIN_INVISIBLE; + else + pinList[i]->m_attributes |= PIN_INVISIBLE; + + SetModified(); + } +} + + +void LIB_PIN::EnableEditMode( bool enable, bool editPinByPin ) +{ + LIB_PINS pinList; + + if( GetParent() == NULL ) + return; + + GetParent()->GetPins( pinList ); + + for( size_t i = 0; i < pinList.size(); i++ ) + { + if( pinList[i] == this ) + continue; + + if( ( pinList[i]->m_position == m_position ) + && ( pinList[i]->m_orientation == m_orientation ) + && !IsNew() + && editPinByPin == false + && enable ) + pinList[i]->SetFlags( IS_LINKED | IN_EDIT ); + else + pinList[i]->ClearFlags( IS_LINKED | IN_EDIT ); + } +} + + +bool LIB_PIN::HitTest( const wxPoint& aPosition ) const +{ + return HitTest( aPosition, 0, DefaultTransform ); +} + + +bool LIB_PIN::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + if( aThreshold < 0 ) + aThreshold = 0; + + TRANSFORM transform = DefaultTransform; + DefaultTransform = aTransform; + + EDA_RECT rect = GetBoundingBox(); + rect.Inflate( aThreshold ); + + //Restore matrix + DefaultTransform = transform; + + return rect.Contains( aPosition ); +} + + +bool LIB_PIN::Save( OUTPUTFORMATTER& aFormatter ) +{ + wxString StringPinNum; + int Etype; + + switch( m_type ) + { + default: + case PIN_INPUT: + Etype = 'I'; + break; + + case PIN_OUTPUT: + Etype = 'O'; + break; + + case PIN_BIDI: + Etype = 'B'; + break; + + case PIN_TRISTATE: + Etype = 'T'; + break; + + case PIN_PASSIVE: + Etype = 'P'; + break; + + case PIN_UNSPECIFIED: + Etype = 'U'; + break; + + case PIN_POWER_IN: + Etype = 'W'; + break; + + case PIN_POWER_OUT: + Etype = 'w'; + break; + + case PIN_OPENCOLLECTOR: + Etype = 'C'; + break; + + case PIN_OPENEMITTER: + Etype = 'E'; + break; + + case PIN_NC: + Etype = 'N'; + break; + } + + PinStringNum( StringPinNum ); + + if( StringPinNum.IsEmpty() ) + StringPinNum = wxT( "~" ); + + if( !m_name.IsEmpty() ) + { + if( aFormatter.Print( 0, "X %s", TO_UTF8( m_name ) ) < 0 ) + return false; + } + else + { + if( aFormatter.Print( 0, "X ~" ) < 0 ) + return false; + } + + if( aFormatter.Print( 0, " %s %d %d %d %c %d %d %d %d %c", + TO_UTF8( StringPinNum ), m_position.x, m_position.y, + (int) m_length, (int) m_orientation, m_numTextSize, m_nameTextSize, + m_Unit, m_Convert, Etype ) < 0 ) + return false; + + if( m_shape || !IsVisible() ) + { + if( aFormatter.Print( 0, " " ) < 0 ) + return false; + } + + if( !IsVisible() && aFormatter.Print( 0, "N" ) < 0 ) + return false; + + if( m_shape & INVERT && aFormatter.Print( 0, "I" ) < 0 ) + return false; + + if( m_shape & CLOCK && aFormatter.Print( 0, "C" ) < 0 ) + return false; + + if( m_shape & LOWLEVEL_IN && aFormatter.Print( 0, "L" ) < 0 ) + return false; + + if( m_shape & LOWLEVEL_OUT && aFormatter.Print( 0, "V" ) < 0 ) + return false; + + if( m_shape & CLOCK_FALL && aFormatter.Print( 0, "F" ) < 0 ) + return false; + + if( m_shape & NONLOGIC && aFormatter.Print( 0, "X" ) < 0 ) + return false; + + if( aFormatter.Print( 0, "\n" ) < 0 ) + return false; + + ClearFlags( IS_CHANGED ); + + return true; +} + +#include + +bool LIB_PIN::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char pinAttrs[64]; + char pinOrient[64]; + char pinType[64]; + + *pinAttrs = 0; + + // We cannot use sscanf, at least on Windows, to parse the pin description. + // The reason is the pin name is free, and use UTF8 encoding. + // We encourtered issues (Windows specific) to read this name for some UTF8 + // cyrillic codes + // So, read the pin name (and num) after conversion from UTF8, and read the others + // parameters (in ASCII) using sscanf + + // the full line starts by "X ". The pin data starts at line + 2. + wxString utf8line = FROM_UTF8( aLineReader.Line() + 2 ); + wxStringTokenizer tokenizer( utf8line, wxT(" \n\r" ) ); + int prms_count = tokenizer.CountTokens(); + + if( prms_count < 11 ) + { + aErrorMsg.Printf( wxT( "pin had %d parameters of the required 11 or 12" ), prms_count ); + return false; + } + + // Extract the pinName (UTF8 encoded) + m_name = tokenizer.GetNextToken(); + + wxString tmp; + + // Extract the pinName (UTF8 encoded accepted, but should be only ASCII8.) + tmp = tokenizer.GetNextToken(); + SetPinNumFromString( tmp ); + + // Read other parameters, in pure ASCII + char line[1024]; + tmp = tokenizer.GetString(); + + unsigned len = tmp.Length(); + + if( len >= sizeof( line ) ) // Should not occur. + len = sizeof( line) - 1; + + strncpy( line, TO_UTF8( tmp ), len ); + line[len] = 0; + + int cnt = sscanf( line, "%d %d %d %63s %d %d %d %d %63s %63s", + &m_position.x, &m_position.y, &m_length, pinOrient, &m_numTextSize, + &m_nameTextSize, &m_Unit, &m_Convert, pinType, pinAttrs ); + + if( cnt != (prms_count - 2) ) + { + aErrorMsg.Printf( wxT( "pin parameters read issue" ) ); + return false; + } + + m_orientation = pinOrient[0] & 255; + + switch( *pinType & 255 ) + { + case 'I': + m_type = PIN_INPUT; + break; + + case 'O': + m_type = PIN_OUTPUT; + break; + + case 'B': + m_type = PIN_BIDI; + break; + + case 'T': + m_type = PIN_TRISTATE; + break; + + case 'P': + m_type = PIN_PASSIVE; + break; + + case 'U': + m_type = PIN_UNSPECIFIED; + break; + + case 'W': + m_type = PIN_POWER_IN; + break; + + case 'w': + m_type = PIN_POWER_OUT; + break; + + case 'C': + m_type = PIN_OPENCOLLECTOR; + break; + + case 'E': + m_type = PIN_OPENEMITTER; + break; + + case 'N': + m_type = PIN_NC; + break; + + default: + aErrorMsg.Printf( wxT( "unknown pin type [%c]" ), *pinType & 255 ); + return false; + } + + if( prms_count >= 12 ) /* Special Symbol defined */ + { + for( int j = strlen( pinAttrs ); j > 0; ) + { + switch( pinAttrs[--j] ) + { + case '~': + break; + + case 'N': + m_attributes |= PIN_INVISIBLE; + break; + + case 'I': + m_shape |= INVERT; + break; + + case 'C': + m_shape |= CLOCK; + break; + + case 'L': + m_shape |= LOWLEVEL_IN; + break; + + case 'V': + m_shape |= LOWLEVEL_OUT; + break; + + case 'F': + m_shape |= CLOCK_FALL; + break; + + case 'X': + m_shape |= NONLOGIC; + break; + + default: + aErrorMsg.Printf( wxT( "unknown pin attribute [%c]" ), pinAttrs[j] ); + return false; + } + } + } + + return true; +} + + +int LIB_PIN::GetPenSize() const +{ + return ( m_width == 0 ) ? GetDefaultLineThickness() : m_width; +} + + +void LIB_PIN::drawGraphic( EDA_DRAW_PANEL* aPanel, + wxDC* aDC, + const wxPoint& aOffset, + EDA_COLOR_T aColor, + GR_DRAWMODE aDrawMode, + void* aData, + const TRANSFORM& aTransform ) +{ + // aData is used here as a bitfield of flags. + uintptr_t flags = (uintptr_t) aData; + bool drawPinText = flags & PIN_DRAW_TEXTS; + bool drawPinDangling = flags & PIN_DRAW_DANGLING; + bool drawDanglingHidden = flags & PIN_DANGLING_HIDDEN; + + LIB_PART* Entry = GetParent(); + + /* Calculate pin orient taking in account the component orientation. */ + int orient = PinDrawOrient( aTransform ); + + /* Calculate the pin position */ + wxPoint pos1 = aTransform.TransformCoordinate( m_position ) + aOffset; + + // Invisible pins are only drawn on request. + // They are drawn in GetInvisibleItemColor(). + // in schematic, they are drawn only if m_showAllPins is true. + // In other windows, they are always drawn because we must see them. + if( ! IsVisible() ) + { + EDA_DRAW_FRAME* frame = NULL; + + if( aPanel && aPanel->GetParent() ) + frame = (EDA_DRAW_FRAME*)aPanel->GetParent(); + + if( frame && frame->IsType( FRAME_SCH ) && + ! ((SCH_EDIT_FRAME*)frame)->GetShowAllPins() ) + { + if( drawPinDangling && drawDanglingHidden ) + { + // Draw the target + DrawPinSymbol( aPanel, aDC, pos1, orient, aDrawMode, aColor, drawPinDangling, + /* aOnlyTarget */ true ); + } + return; + } + + aColor = GetInvisibleItemColor(); + } + + /* Drawing from the pin and the special symbol combination */ + DrawPinSymbol( aPanel, aDC, pos1, orient, aDrawMode, aColor, drawPinDangling ); + + if( drawPinText ) + { + DrawPinTexts( aPanel, aDC, pos1, orient, Entry->GetPinNameOffset(), + Entry->ShowPinNumbers(), Entry->ShowPinNames(), + aColor, aDrawMode ); + } + + /* Set to one (1) to draw bounding box around pin to validate bounding + * box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( aPanel ? aPanel->GetClipBox() : NULL, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +void LIB_PIN::DrawPinSymbol( EDA_DRAW_PANEL* aPanel, + wxDC* aDC, + const wxPoint& aPinPos, + int aOrient, + GR_DRAWMODE aDrawMode, + EDA_COLOR_T aColor, + bool aDrawDangling, + bool aOnlyTarget ) +{ + int MapX1, MapY1, x1, y1; + int width = GetPenSize(); + int posX = aPinPos.x, posY = aPinPos.y, len = m_length; + EDA_RECT* clipbox = aPanel ? aPanel->GetClipBox() : NULL; + + EDA_COLOR_T color = GetLayerColor( LAYER_PIN ); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + color = aColor; + + GRSetDrawMode( aDC, aDrawMode ); + + MapX1 = MapY1 = 0; + x1 = posX; + y1 = posY; + + switch( aOrient ) + { + case PIN_UP: + y1 = posY - len; + MapY1 = 1; + break; + + case PIN_DOWN: + y1 = posY + len; + MapY1 = -1; + break; + + case PIN_LEFT: + x1 = posX - len; + MapX1 = 1; + break; + + case PIN_RIGHT: + x1 = posX + len; + MapX1 = -1; + break; + } + + // Draw the pin end target (active end of the pin) + BASE_SCREEN* screen = aPanel ? aPanel->GetScreen() : NULL; + #define NCSYMB_PIN_DIM TARGET_PIN_RADIUS + + // Draw but do not print the pin end target 1 pixel width + if( m_type != PIN_NC && ( screen == NULL || !screen->m_IsPrinting ) ) + { + if( aDrawDangling ) + GRCircle( clipbox, aDC, posX, posY, TARGET_PIN_RADIUS, 0, color ); + } + + if( aOnlyTarget ) + return; + + + if( m_shape & INVERT ) + { + const int radius = ExternalPinDecoSize( *this ); + GRCircle( clipbox, aDC, MapX1 * radius + x1, + MapY1 * radius + y1, + radius, width, color ); + + GRMoveTo( MapX1 * radius * 2 + x1, + MapY1 * radius * 2 + y1 ); + GRLineTo( clipbox, aDC, posX, posY, width, color ); + } + else if( m_shape & CLOCK_FALL ) /* an alternative for Inverted Clock */ + { + const int clock_size = InternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + GRMoveTo( x1, y1 + clock_size ); + GRLineTo( clipbox, aDC, x1 + MapX1 * clock_size * 2, y1, + width, color ); + GRLineTo( clipbox, aDC, x1, y1 - clock_size, width, color ); + } + else /* MapX1 = 0 */ + { + GRMoveTo( x1 + clock_size, y1 ); + GRLineTo( clipbox, aDC, x1, y1 + MapY1 * clock_size * 2, + width, color ); + GRLineTo( clipbox, aDC, x1 - clock_size, y1, + width, color ); + } + GRMoveTo( MapX1 * clock_size * 2 + x1, MapY1 * clock_size * 2 + y1 ); + GRLineTo( clipbox, aDC, posX, posY, width, color ); + } + else + { + GRMoveTo( x1, y1 ); + GRLineTo( clipbox, aDC, posX, posY, width, color ); + } + + if( m_shape & CLOCK ) + { + const int clock_size = InternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + GRMoveTo( x1, y1 + clock_size ); + GRLineTo( clipbox, aDC, x1 - MapX1 * clock_size * 2, y1, + width, color ); + GRLineTo( clipbox, aDC, x1, y1 - clock_size, + width, color ); + } + else /* MapX1 = 0 */ + { + GRMoveTo( x1 + clock_size, y1 ); + GRLineTo( clipbox, aDC, x1, y1 - MapY1 * clock_size * 2, + width, color ); + GRLineTo( clipbox, aDC, x1 - clock_size, y1, + width, color ); + } + } + + if( m_shape & LOWLEVEL_IN ) /* IEEE symbol "Active Low Input" */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + GRMoveTo( x1 + MapX1 * symbol_size * 2, y1 ); + GRLineTo( clipbox, aDC, + x1 + MapX1 * symbol_size * 2, y1 - symbol_size * 2, + width, color ); + GRLineTo( clipbox, aDC, x1, y1, width, color ); + } + else /* MapX1 = 0 */ + { + GRMoveTo( x1, y1 + MapY1 * symbol_size * 2 ); + GRLineTo( clipbox, aDC, x1 - symbol_size * 2, + y1 + MapY1 * symbol_size * 2, width, color ); + GRLineTo( clipbox, aDC, x1, y1, width, color ); + } + } + + + if( m_shape & LOWLEVEL_OUT ) /* IEEE symbol "Active Low Output" */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + GRMoveTo( x1, y1 - symbol_size * 2 ); + GRLineTo( clipbox, + aDC, + x1 + MapX1 * symbol_size * 2, + y1, + width, + color ); + } + else /* MapX1 = 0 */ + { + GRMoveTo( x1 - symbol_size * 2, y1 ); + GRLineTo( clipbox, aDC, x1, y1 + MapY1 * symbol_size * 2, + width, color ); + } + } + else if( m_shape & NONLOGIC ) /* NonLogic pin symbol */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + GRMoveTo( x1 - (MapX1 + MapY1) * symbol_size, + y1 - (MapY1 - MapX1) * symbol_size ); + GRLineTo( clipbox, aDC, + x1 + (MapX1 + MapY1) * symbol_size, + y1 + (MapY1 - MapX1) * symbol_size, + width, color ); + GRMoveTo( x1 - (MapX1 - MapY1) * symbol_size, + y1 - (MapY1 + MapX1) * symbol_size ); + GRLineTo( clipbox, aDC, + x1 + (MapX1 - MapY1) * symbol_size, + y1 + (MapY1 + MapX1) * symbol_size, + width, color ); + } + + if( m_type == PIN_NC ) // Draw a N.C. symbol + { + GRLine( clipbox, aDC, + posX - NCSYMB_PIN_DIM, posY - NCSYMB_PIN_DIM, + posX + NCSYMB_PIN_DIM, posY + NCSYMB_PIN_DIM, + width, color ); + GRLine( clipbox, aDC, + posX + NCSYMB_PIN_DIM, posY - NCSYMB_PIN_DIM, + posX - NCSYMB_PIN_DIM, posY + NCSYMB_PIN_DIM, + width, color ); + } +} + + +void LIB_PIN::DrawPinTexts( EDA_DRAW_PANEL* panel, + wxDC* DC, + wxPoint& pin_pos, + int orient, + int TextInside, + bool DrawPinNum, + bool DrawPinName, + EDA_COLOR_T Color, + GR_DRAWMODE DrawMode ) +{ + if( !DrawPinName && !DrawPinNum ) + return; + + int x, y; + wxString StringPinNum; + + wxSize PinNameSize( m_nameTextSize, m_nameTextSize ); + wxSize PinNumSize( m_numTextSize, m_numTextSize ); + + int nameLineWidth = GetPenSize(); + + nameLineWidth = Clamp_Text_PenSize( nameLineWidth, m_nameTextSize, false ); + int numLineWidth = GetPenSize(); + numLineWidth = Clamp_Text_PenSize( numLineWidth, m_numTextSize, false ); + + GRSetDrawMode( DC, DrawMode ); + EDA_RECT* clipbox = panel? panel->GetClipBox() : NULL; + + /* Get the num and name colors */ + if( (Color < 0) && IsSelected() ) + Color = GetItemSelectedColor(); + + EDA_COLOR_T NameColor = Color == UNSPECIFIED_COLOR ? + GetLayerColor( LAYER_PINNAM ) : Color; + EDA_COLOR_T NumColor = Color == UNSPECIFIED_COLOR ? + GetLayerColor( LAYER_PINNUM ) : Color; + + /* Create the pin num string */ + PinStringNum( StringPinNum ); + + int x1 = pin_pos.x; + int y1 = pin_pos.y; + + switch( orient ) + { + case PIN_UP: + y1 -= m_length; + break; + + case PIN_DOWN: + y1 += m_length; + break; + + case PIN_LEFT: + x1 -= m_length; + break; + + case PIN_RIGHT: + x1 += m_length; + break; + } + + if( m_name.IsEmpty() ) + DrawPinName = false; + + if( TextInside ) // Draw the text inside, but the pin numbers outside. + { + if( (orient == PIN_LEFT) || (orient == PIN_RIGHT) ) + { + // It is an horizontal line + if( DrawPinName ) + { + if( orient == PIN_RIGHT ) + { + x = x1 + TextInside; + DrawGraphicText( clipbox, DC, wxPoint( x, y1 ), NameColor, + m_name, + TEXT_ORIENT_HORIZ, + PinNameSize, + GR_TEXT_HJUSTIFY_LEFT, + GR_TEXT_VJUSTIFY_CENTER, nameLineWidth, + false, false ); + } + else // Orient == PIN_LEFT + { + x = x1 - TextInside; + DrawGraphicText( clipbox, DC, wxPoint( x, y1 ), NameColor, + m_name, + TEXT_ORIENT_HORIZ, + PinNameSize, + GR_TEXT_HJUSTIFY_RIGHT, + GR_TEXT_VJUSTIFY_CENTER, nameLineWidth, + false, false ); + } + } + + if( DrawPinNum ) + { + DrawGraphicText( clipbox, DC, + wxPoint( (x1 + pin_pos.x) / 2, + y1 - TXTMARGE ), NumColor, + StringPinNum, + TEXT_ORIENT_HORIZ, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, numLineWidth, + false, false ); + } + } + else /* Its a vertical line. */ + { + // Text is drawn from bottom to top (i.e. to negative value for Y axis) + if( orient == PIN_DOWN ) + { + y = y1 + TextInside; + + if( DrawPinName ) + DrawGraphicText( clipbox, DC, wxPoint( x1, y ), NameColor, + m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_RIGHT, + GR_TEXT_VJUSTIFY_CENTER, nameLineWidth, + false, false ); + + if( DrawPinNum ) + DrawGraphicText( clipbox, DC, + wxPoint( x1 - TXTMARGE, + (y1 + pin_pos.y) / 2 ), NumColor, + StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, numLineWidth, + false, false ); + } + else /* PIN_UP */ + { + y = y1 - TextInside; + + if( DrawPinName ) + DrawGraphicText( clipbox, DC, wxPoint( x1, y ), NameColor, + m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_LEFT, + GR_TEXT_VJUSTIFY_CENTER, nameLineWidth, + false, false ); + + if( DrawPinNum ) + DrawGraphicText( clipbox, DC, + wxPoint( x1 - TXTMARGE, + (y1 + pin_pos.y) / 2 ), NumColor, + StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, numLineWidth, + false, false ); + } + } + } + else /**** Draw num & text pin outside ****/ + { + if( (orient == PIN_LEFT) || (orient == PIN_RIGHT) ) + { + /* Its an horizontal line. */ + if( DrawPinName ) + { + x = (x1 + pin_pos.x) / 2; + DrawGraphicText( clipbox, DC, wxPoint( x, y1 - TXTMARGE ), + NameColor, m_name, + TEXT_ORIENT_HORIZ, PinNameSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, nameLineWidth, + false, false ); + } + if( DrawPinNum ) + { + x = (x1 + pin_pos.x) / 2; + DrawGraphicText( clipbox, DC, wxPoint( x, y1 + TXTMARGE ), + NumColor, StringPinNum, + TEXT_ORIENT_HORIZ, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP, numLineWidth, + false, false ); + } + } + else /* Its a vertical line. */ + { + if( DrawPinName ) + { + y = (y1 + pin_pos.y) / 2; + DrawGraphicText( clipbox, DC, wxPoint( x1 - TXTMARGE, y ), + NameColor, m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, nameLineWidth, + false, false ); + } + + if( DrawPinNum ) + { + DrawGraphicText( clipbox, DC, + wxPoint( x1 + TXTMARGE, (y1 + pin_pos.y) / 2 ), + NumColor, StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP, numLineWidth, + false, false ); + } + } + } +} + + +void LIB_PIN::PlotSymbol( PLOTTER* aPlotter, const wxPoint& aPosition, int aOrientation ) +{ + int MapX1, MapY1, x1, y1; + EDA_COLOR_T color = GetLayerColor( LAYER_PIN ); + + aPlotter->SetColor( color ); + aPlotter->SetCurrentLineWidth( GetPenSize() ); + + MapX1 = MapY1 = 0; + x1 = aPosition.x; y1 = aPosition.y; + + switch( aOrientation ) + { + case PIN_UP: + y1 = aPosition.y - m_length; + MapY1 = 1; + break; + + case PIN_DOWN: + y1 = aPosition.y + m_length; + MapY1 = -1; + break; + + case PIN_LEFT: + x1 = aPosition.x - m_length; + MapX1 = 1; + break; + + case PIN_RIGHT: + x1 = aPosition.x + m_length; + MapX1 = -1; + break; + } + + if( m_shape & INVERT ) + { + const int radius = ExternalPinDecoSize( *this ); + aPlotter->Circle( wxPoint( MapX1 * radius + x1, + MapY1 * radius + y1 ), + radius * 2, // diameter + NO_FILL, // fill option + GetPenSize() ); // width + + aPlotter->MoveTo( wxPoint( MapX1 * radius * 2 + x1, + MapY1 * radius * 2 + y1 ) ); + aPlotter->FinishTo( aPosition ); + } + else if( m_shape & CLOCK_FALL ) + { + const int clock_size = InternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + aPlotter->MoveTo( wxPoint( x1, y1 + clock_size ) ); + aPlotter->LineTo( wxPoint( x1 + MapX1 * clock_size * 2, y1 ) ); + aPlotter->FinishTo( wxPoint( x1, y1 - clock_size ) ); + } + else /* MapX1 = 0 */ + { + aPlotter->MoveTo( wxPoint( x1 + clock_size, y1 ) ); + aPlotter->LineTo( wxPoint( x1, y1 + MapY1 * clock_size * 2 ) ); + aPlotter->FinishTo( wxPoint( x1 - clock_size, y1 ) ); + } + + aPlotter->MoveTo( wxPoint( MapX1 * clock_size * 2 + x1, + MapY1 * clock_size * 2 + y1 ) ); + aPlotter->FinishTo( aPosition ); + } + else + { + aPlotter->MoveTo( wxPoint( x1, y1 ) ); + aPlotter->FinishTo( aPosition ); + } + + if( m_shape & CLOCK ) + { + const int clock_size = InternalPinDecoSize( *this ); + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + aPlotter->MoveTo( wxPoint( x1, y1 + clock_size ) ); + aPlotter->LineTo( wxPoint( x1 - MapX1 * clock_size * 2, y1 ) ); + aPlotter->FinishTo( wxPoint( x1, y1 - clock_size ) ); + } + else /* MapX1 = 0 */ + { + aPlotter->MoveTo( wxPoint( x1 + clock_size, y1 ) ); + aPlotter->LineTo( wxPoint( x1, y1 - MapY1 * clock_size * 2 ) ); + aPlotter->FinishTo( wxPoint( x1 - clock_size, y1 ) ); + } + } + + if( m_shape & LOWLEVEL_IN ) /* IEEE symbol "Active Low Input" */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + aPlotter->MoveTo( wxPoint( x1 + MapX1 * symbol_size * 2, y1 ) ); + aPlotter->LineTo( wxPoint( x1 + MapX1 * symbol_size * 2, + y1 - symbol_size * 2 ) ); + aPlotter->FinishTo( wxPoint( x1, y1 ) ); + } + else /* MapX1 = 0 */ + { + aPlotter->MoveTo( wxPoint( x1, y1 + MapY1 * symbol_size * 2 ) ); + aPlotter->LineTo( wxPoint( x1 - symbol_size * 2, + y1 + MapY1 * symbol_size * 2 ) ); + aPlotter->FinishTo( wxPoint( x1, y1 ) ); + } + } + + + if( m_shape & LOWLEVEL_OUT ) /* IEEE symbol "Active Low Output" */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + + if( MapY1 == 0 ) /* MapX1 = +- 1 */ + { + aPlotter->MoveTo( wxPoint( x1, y1 - symbol_size * 2 ) ); + aPlotter->FinishTo( wxPoint( x1 + MapX1 * symbol_size * 2, y1 ) ); + } + else /* MapX1 = 0 */ + { + aPlotter->MoveTo( wxPoint( x1 - symbol_size * 2, y1 ) ); + aPlotter->FinishTo( wxPoint( x1, y1 + MapY1 * symbol_size * 2 ) ); + } + } + else if( m_shape & NONLOGIC ) /* NonLogic pin symbol */ + { + const int symbol_size = ExternalPinDecoSize( *this ); + aPlotter->MoveTo( wxPoint( x1 - (MapX1 + MapY1) * symbol_size, + y1 - (MapY1 - MapX1) * symbol_size ) ); + aPlotter->FinishTo( wxPoint( x1 + (MapX1 + MapY1) * symbol_size, + y1 + (MapY1 - MapX1) * symbol_size ) ); + aPlotter->MoveTo( wxPoint( x1 - (MapX1 - MapY1) * symbol_size, + y1 - (MapY1 + MapX1) * symbol_size ) ); + aPlotter->FinishTo( wxPoint( x1 + (MapX1 - MapY1) * symbol_size, + y1 + (MapY1 + MapX1) * symbol_size ) ); + } + if( m_type == PIN_NC ) // Draw a N.C. symbol + { + const int ex1 = aPosition.x; + const int ey1 = aPosition.y; + aPlotter->MoveTo( wxPoint( ex1 - NCSYMB_PIN_DIM, ey1 - NCSYMB_PIN_DIM ) ); + aPlotter->FinishTo( wxPoint( ex1 + NCSYMB_PIN_DIM, ey1 + NCSYMB_PIN_DIM ) ); + aPlotter->MoveTo( wxPoint( ex1 + NCSYMB_PIN_DIM, ey1 - NCSYMB_PIN_DIM ) ); + aPlotter->FinishTo( wxPoint( ex1 - NCSYMB_PIN_DIM, ey1 + NCSYMB_PIN_DIM ) ); + } +} + + +void LIB_PIN::PlotPinTexts( PLOTTER* plotter, wxPoint& pin_pos, int orient, + int TextInside, bool DrawPinNum, + bool DrawPinName, int aWidth ) +{ + if( m_name.IsEmpty() || m_name == wxT( "~" ) ) + DrawPinName = false; + + /* Create the pin num string */ + wxString StringPinNum; + PinStringNum( StringPinNum ); + + if( StringPinNum.IsEmpty() ) + DrawPinNum = false; + + if( !DrawPinNum && !DrawPinName ) + return; + + int x, y; + wxSize PinNameSize = wxSize( m_nameTextSize, m_nameTextSize ); + wxSize PinNumSize = wxSize( m_numTextSize, m_numTextSize ); + + /* Get the num and name colors */ + EDA_COLOR_T NameColor = GetLayerColor( LAYER_PINNAM ); + EDA_COLOR_T NumColor = GetLayerColor( LAYER_PINNUM ); + + int x1 = pin_pos.x; + int y1 = pin_pos.y; + + switch( orient ) + { + case PIN_UP: + y1 -= m_length; + break; + + case PIN_DOWN: + y1 += m_length; + break; + + case PIN_LEFT: + x1 -= m_length; + break; + + case PIN_RIGHT: + x1 += m_length; + break; + } + + /* Draw the text inside, but the pin numbers outside. */ + if( TextInside ) + { + if( (orient == PIN_LEFT) || (orient == PIN_RIGHT) ) /* Its an horizontal line. */ + { + if( DrawPinName ) + { + if( orient == PIN_RIGHT ) + { + x = x1 + TextInside; + plotter->Text( wxPoint( x, y1 ), NameColor, + m_name, + TEXT_ORIENT_HORIZ, + PinNameSize, + GR_TEXT_HJUSTIFY_LEFT, + GR_TEXT_VJUSTIFY_CENTER, + aWidth, false, false ); + } + else // orient == PIN_LEFT + { + x = x1 - TextInside; + + if( DrawPinName ) + plotter->Text( wxPoint( x, y1 ), + NameColor, m_name, TEXT_ORIENT_HORIZ, + PinNameSize, + GR_TEXT_HJUSTIFY_RIGHT, + GR_TEXT_VJUSTIFY_CENTER, + aWidth, false, false ); + } + } + if( DrawPinNum ) + { + plotter->Text( wxPoint( (x1 + pin_pos.x) / 2, y1 - TXTMARGE ), + NumColor, StringPinNum, + TEXT_ORIENT_HORIZ, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, + aWidth, false, false ); + } + } + else /* Its a vertical line. */ + { + if( orient == PIN_DOWN ) + { + y = y1 + TextInside; + + if( DrawPinName ) + plotter->Text( wxPoint( x1, y ), NameColor, + m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_RIGHT, + GR_TEXT_VJUSTIFY_CENTER, + aWidth, false, false ); + + if( DrawPinNum ) + { + plotter->Text( wxPoint( x1 - TXTMARGE, (y1 + pin_pos.y) / 2 ), + NumColor, StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, + aWidth, false, false ); + } + } + else /* PIN_UP */ + { + y = y1 - TextInside; + + if( DrawPinName ) + plotter->Text( wxPoint( x1, y ), NameColor, + m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_LEFT, + GR_TEXT_VJUSTIFY_CENTER, + aWidth, false, false ); + + if( DrawPinNum ) + { + plotter->Text( wxPoint( x1 - TXTMARGE, (y1 + pin_pos.y) / 2 ), + NumColor, StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, + aWidth, false, false ); + } + } + } + } + else /* Draw num & text pin outside */ + { + if( (orient == PIN_LEFT) || (orient == PIN_RIGHT) ) + { + /* Its an horizontal line. */ + if( DrawPinName ) + { + x = (x1 + pin_pos.x) / 2; + plotter->Text( wxPoint( x, y1 - TXTMARGE ), + NameColor, m_name, + TEXT_ORIENT_HORIZ, PinNameSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, + aWidth, false, false ); + } + + if( DrawPinNum ) + { + x = ( x1 + pin_pos.x ) / 2; + plotter->Text( wxPoint( x, y1 + TXTMARGE ), + NumColor, StringPinNum, + TEXT_ORIENT_HORIZ, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP, + aWidth, false, false ); + } + } + else /* Its a vertical line. */ + { + if( DrawPinName ) + { + y = ( y1 + pin_pos.y ) / 2; + plotter->Text( wxPoint( x1 - TXTMARGE, y ), + NameColor, m_name, + TEXT_ORIENT_VERT, PinNameSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_BOTTOM, + aWidth, false, false ); + } + + if( DrawPinNum ) + { + plotter->Text( wxPoint( x1 + TXTMARGE, ( y1 + pin_pos.y ) / 2 ), + NumColor, StringPinNum, + TEXT_ORIENT_VERT, PinNumSize, + GR_TEXT_HJUSTIFY_CENTER, + GR_TEXT_VJUSTIFY_TOP, + aWidth, false, false ); + } + } + } +} + + +wxPoint LIB_PIN::PinEndPoint() const +{ + wxPoint pos = m_position; + + switch( m_orientation ) + { + case PIN_UP: + pos.y += m_length; + break; + + case PIN_DOWN: + pos.y -= m_length; + break; + + case PIN_LEFT: + pos.x -= m_length; + break; + + case PIN_RIGHT: + pos.x += m_length; + break; + } + + return pos; +} + + +int LIB_PIN::PinDrawOrient( const TRANSFORM& aTransform ) const +{ + int orient; + wxPoint end; // position of pin end starting at 0,0 according to its orientation, length = 1 + + switch( m_orientation ) + { + case PIN_UP: + end.y = 1; + break; + + case PIN_DOWN: + end.y = -1; + break; + + case PIN_LEFT: + end.x = -1; + break; + + case PIN_RIGHT: + end.x = 1; + break; + } + + // = pos of end point, according to the component orientation + end = aTransform.TransformCoordinate( end ); + orient = PIN_UP; + + if( end.x == 0 ) + { + if( end.y > 0 ) + orient = PIN_DOWN; + } + else + { + orient = PIN_RIGHT; + + if( end.x < 0 ) + orient = PIN_LEFT; + } + + return orient; +} + + +void LIB_PIN::PinStringNum( wxString& aStringBuffer ) const +{ + aStringBuffer = PinStringNum( m_number ); +} + + +wxString LIB_PIN::PinStringNum( long aPinNum ) +{ + char ascii_buf[5]; + + memcpy( ascii_buf, &aPinNum, 4 ); + ascii_buf[4] = 0; + + wxString buffer = FROM_UTF8( ascii_buf ); + + return buffer; +} + + +void LIB_PIN::SetPinNumFromString( wxString& buffer ) +{ + char ascii_buf[4]; + unsigned ii, len = buffer.Len(); + + ascii_buf[0] = ascii_buf[1] = ascii_buf[2] = ascii_buf[3] = 0; + + if( len > 4 ) + len = 4; + + for( ii = 0; ii < len; ii++ ) + { + ascii_buf[ii] = buffer.GetChar( ii ); + ascii_buf[ii] &= 0xFF; + } + + strncpy( (char*) &m_number, ascii_buf, 4 ); +} + + +EDA_ITEM* LIB_PIN::Clone() const +{ + return new LIB_PIN( *this ); +} + + +int LIB_PIN::compare( const LIB_ITEM& other ) const +{ + wxASSERT( other.Type() == LIB_PIN_T ); + + const LIB_PIN* tmp = (LIB_PIN*) &other; + + if( m_number != tmp->m_number ) + return m_number - tmp->m_number; + + int result = m_name.CmpNoCase( tmp->m_name ); + + if( result != 0 ) + return result; + + if( m_position.x != tmp->m_position.x ) + return m_position.x - tmp->m_position.x; + + if( m_position.y != tmp->m_position.y ) + return m_position.y - tmp->m_position.y; + + return 0; +} + + +void LIB_PIN::SetOffset( const wxPoint& aOffset ) +{ + m_position += aOffset; +} + + +bool LIB_PIN::Inside( EDA_RECT& rect ) const +{ + wxPoint end = PinEndPoint(); + + return rect.Contains( m_position.x, -m_position.y ) || rect.Contains( end.x, -end.y ); +} + + +void LIB_PIN::Move( const wxPoint& newPosition ) +{ + if( m_position != newPosition ) + { + m_position = newPosition; + SetModified(); + } +} + + +void LIB_PIN::MirrorHorizontal( const wxPoint& center ) +{ + m_position.x -= center.x; + m_position.x *= -1; + m_position.x += center.x; + + if( m_orientation == PIN_RIGHT ) + m_orientation = PIN_LEFT; + else if( m_orientation == PIN_LEFT ) + m_orientation = PIN_RIGHT; +} + +void LIB_PIN::MirrorVertical( const wxPoint& center ) +{ + m_position.y -= center.y; + m_position.y *= -1; + m_position.y += center.y; + + if( m_orientation == PIN_UP ) + m_orientation = PIN_DOWN; + else if( m_orientation == PIN_DOWN ) + m_orientation = PIN_UP; +} + +void LIB_PIN::Rotate( const wxPoint& center, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + + RotatePoint( &m_position, center, rot_angle ); + + if( aRotateCCW ) + { + switch( m_orientation ) + { + case PIN_RIGHT: + m_orientation = PIN_UP; + break; + + case PIN_UP: + m_orientation = PIN_LEFT; + break; + case PIN_LEFT: + m_orientation = PIN_DOWN; + break; + + case PIN_DOWN: + m_orientation = PIN_RIGHT; + break; + } + } + else + { + switch( m_orientation ) + { + case PIN_RIGHT: + m_orientation = PIN_DOWN; + break; + + case PIN_UP: + m_orientation = PIN_RIGHT; + break; + case PIN_LEFT: + m_orientation = PIN_UP; + break; + + case PIN_DOWN: + m_orientation = PIN_LEFT; + break; + } + } +} + + +void LIB_PIN::Plot( PLOTTER* plotter, const wxPoint& offset, bool fill, + const TRANSFORM& aTransform ) +{ + if( ! IsVisible() ) + return; + + int orient = PinDrawOrient( aTransform ); + + wxPoint pos = aTransform.TransformCoordinate( m_position ) + offset; + + PlotSymbol( plotter, pos, orient ); + PlotPinTexts( plotter, pos, orient, GetParent()->GetPinNameOffset(), + GetParent()->ShowPinNumbers(), GetParent()->ShowPinNames(), + GetPenSize() ); +} + + +void LIB_PIN::SetWidth( int aWidth ) +{ + if( m_width != aWidth ) + { + m_width = aWidth; + SetModified(); + } +} + + +void LIB_PIN::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString text; + + LIB_ITEM::GetMsgPanelInfo( aList ); + + aList.push_back( MSG_PANEL_ITEM( _( "Name" ), m_name, DARKCYAN ) ); + + if( m_number == 0 ) + text = wxT( "?" ); + else + PinStringNum( text ); + + aList.push_back( MSG_PANEL_ITEM( _( "Number" ), text, DARKCYAN ) ); + + aList.push_back( MSG_PANEL_ITEM( _( "Type" ), + LIB_PIN::GetElectricalTypeName( m_type ), + RED ) ); + + int styleCodeIndex = GetStyleCodeIndex( m_shape ); + + if( styleCodeIndex >= 0 ) + text = getPinStyleName( styleCodeIndex ); + else + text = wxT( "?" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Style" ), text, BLUE ) ); + + if( IsVisible() ) + text = _( "Yes" ); + else + text = _( "No" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Visible" ), text, DARKGREEN ) ); + + // Display pin length + text = StringFromValue( g_UserUnit, m_length, true ); + aList.push_back( MSG_PANEL_ITEM( _( "Length" ), text, MAGENTA ) ); + + text = getPinOrientationName( (unsigned) GetOrientationCodeIndex( m_orientation ) ); + aList.push_back( MSG_PANEL_ITEM( _( "Orientation" ), text, DARKMAGENTA ) ); +} + + +const EDA_RECT LIB_PIN::GetBoundingBox() const +{ + LIB_PART* entry = (LIB_PART* ) m_Parent; + EDA_RECT bbox; + wxPoint begin; + wxPoint end; + int nameTextOffset = 0; + bool showName = !m_name.IsEmpty() && (m_name != wxT( "~" )); + bool showNum = m_number != 0; + int minsizeV = TARGET_PIN_RADIUS; + + + if( entry ) + { + if( entry->ShowPinNames() ) + nameTextOffset = entry->GetPinNameOffset(); + else + showName = false; + + showNum = entry->ShowPinNumbers(); + } + + // First, calculate boundary box corners position + int numberTextLength = showNum ? m_numTextSize * GetNumberString().Len() : 0; + + // Actual text height is bigger than text size + int numberTextHeight = showNum ? KiROUND( m_numTextSize * 1.1 ) : 0; + + if( m_shape & INVERT ) + minsizeV = std::max( TARGET_PIN_RADIUS, ExternalPinDecoSize( *this ) ); + + // calculate top left corner position + // for the default pin orientation (PIN_RIGHT) + begin.y = std::max( minsizeV, numberTextHeight + TXTMARGE ); + begin.x = std::min( -TARGET_PIN_RADIUS, m_length - (numberTextLength / 2) ); + + // calculate bottom right corner position and adjust top left corner position + int nameTextLength = 0; + int nameTextHeight = 0; + + if( showName ) + { + int length = m_name.Len(); + + // Don't count the line over text symbol. + if( m_name.Left( 1 ) == wxT( "~" ) ) + length -= 1; + + nameTextLength = ( m_nameTextSize * length ) + nameTextOffset; + + // Actual text height are bigger than text size + nameTextHeight = KiROUND( m_nameTextSize * 1.1 ) + TXTMARGE; + } + + if( nameTextOffset ) // for values > 0, pin name is inside the body + { + end.x = m_length + nameTextLength; + end.y = std::min( -minsizeV, -nameTextHeight / 2 ); + } + else // if value == 0: + // pin name is outside the body, and above the pin line + // pin num is below the pin line + { + end.x = std::max(m_length, nameTextLength); + end.y = -begin.y; + begin.y = std::max( minsizeV, nameTextHeight ); + } + + // Now, calculate boundary box corners position for the actual pin orientation + int orient = PinDrawOrient( DefaultTransform ); + + /* Calculate the pin position */ + switch( orient ) + { + case PIN_UP: + // Pin is rotated and texts positions are mirrored + RotatePoint( &begin, wxPoint( 0, 0 ), -900 ); + RotatePoint( &end, wxPoint( 0, 0 ), -900 ); + break; + + case PIN_DOWN: + RotatePoint( &begin, wxPoint( 0, 0 ), 900 ); + RotatePoint( &end, wxPoint( 0, 0 ), 900 ); + begin.x = -begin.x; + end.x = -end.x; + break; + + case PIN_LEFT: + begin.x = -begin.x; + end.x = -end.x; + break; + + case PIN_RIGHT: + break; + } + + begin += m_position; + end += m_position; + + bbox.SetOrigin( begin ); + bbox.SetEnd( end ); + bbox.Normalize(); + bbox.Inflate( ( GetPenSize() / 2 ) + 1 ); + + // Draw Y axis is reversed in schematic: + bbox.RevertYAxis(); + + return bbox; +} + + +wxArrayString LIB_PIN::GetOrientationNames( void ) +{ + wxArrayString tmp; + + for( unsigned ii = 0; ii < PIN_ORIENTATION_CNT; ii++ ) + tmp.Add( getPinOrientationName( ii ) ); + + return tmp; +} + + +int LIB_PIN::GetOrientationCode( int index ) +{ + if( index >= 0 && index < (int) PIN_ORIENTATION_CNT ) + return pin_orientation_codes[ index ]; + + return PIN_RIGHT; +} + + +int LIB_PIN::GetOrientationCodeIndex( int code ) +{ + size_t i; + + for( i = 0; i < PIN_ORIENTATION_CNT; i++ ) + { + if( pin_orientation_codes[i] == code ) + return (int) i; + } + + return wxNOT_FOUND; +} + + +void LIB_PIN::Rotate() +{ + int orient = PIN_RIGHT; + + switch( GetOrientation() ) + { + case PIN_UP: + orient = PIN_LEFT; + break; + + case PIN_DOWN: + orient = PIN_RIGHT; + break; + + case PIN_LEFT: + orient = PIN_DOWN; + break; + + case PIN_RIGHT: + orient = PIN_UP; + break; + } + + // Set the new orientation + SetOrientation( orient ); +} + + +wxArrayString LIB_PIN::GetStyleNames( void ) +{ + wxArrayString tmp; + + for( unsigned ii = 0; ii < PIN_STYLE_CNT; ii++ ) + tmp.Add( getPinStyleName( ii ) ); + + return tmp; +} + + +int LIB_PIN::GetStyleCode( int index ) +{ + if( index >= 0 && index < (int) PIN_STYLE_CNT ) + return pin_style_codes[ index ]; + + return NONE; +} + + +int LIB_PIN::GetStyleCodeIndex( int code ) +{ + size_t i; + + for( i = 0; i < PIN_STYLE_CNT; i++ ) + { + if( pin_style_codes[i] == code ) + return (int) i; + } + + return wxNOT_FOUND; +} + + +wxArrayString LIB_PIN::GetElectricalTypeNames( void ) +{ + wxArrayString tmp; + + for( unsigned ii = 0; ii < PIN_ELECTRICAL_TYPE_CNT; ii++ ) + tmp.Add( LIB_PIN::GetElectricalTypeName( ii ) ); + + return tmp; +} + + +const BITMAP_DEF* LIB_PIN::GetElectricalTypeSymbols() +{ + return iconsPinsElectricalType; +} + + +const BITMAP_DEF* LIB_PIN::GetOrientationSymbols() +{ + return iconsPinsOrientations; +} + + +const BITMAP_DEF* LIB_PIN::GetStyleSymbols() +{ + return iconsPinsShapes; +} + + +BITMAP_DEF LIB_PIN::GetMenuImage() const +{ + return iconsPinsElectricalType[m_type]; +} + + +wxString LIB_PIN::GetSelectMenuText() const +{ + wxString tmp; + wxString style; + + int styleCode = GetStyleCodeIndex( m_shape ); + + if( styleCode >= 0 ) + style = getPinStyleName( styleCode ); + else + style = wxT( "?" ); + + tmp.Printf( _( "Pin %s, %s, %s" ), + GetChars( GetNumberString() ), + GetChars( GetElectricalTypeName() ), + GetChars( style ) + ); + return tmp; +} + + +bool LIB_PIN::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ) +{ + wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText() ); + + // Note: this will have to be modified if we add find and replace capability to the + // compoment library editor. Otherwise, you wont be able to replace pin text. + if( !( aSearchData.GetFlags() & FR_SEARCH_ALL_PINS ) + || ( aSearchData.GetFlags() & FR_SEARCH_REPLACE ) ) + return false; + + wxLogTrace( traceFindItem, wxT( " child item " ) + GetSelectMenuText() ); + + if( EDA_ITEM::Matches( GetName(), aSearchData ) + || EDA_ITEM::Matches( GetNumberString(), aSearchData ) ) + { + if( aFindLocation ) + *aFindLocation = GetBoundingBox().Centre(); + + return true; + } + + return false; +} + + +#if defined(DEBUG) + +void LIB_PIN::Show( int nestLevel, std::ostream& os ) const +{ + NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() + << " num=\"" << GetNumberString().mb_str() + << '"' << "/>\n"; + +// NestedSpace( nestLevel, os ) << "\n"; +} + +#endif diff --git a/eeschema/lib_pin.h b/eeschema/lib_pin.h new file mode 100644 index 00000000..6cf68015 --- /dev/null +++ b/eeschema/lib_pin.h @@ -0,0 +1,561 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras at wanadoo.fr + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file class_libentry.h + * @brief Class LIB_PIN definition. + */ +#ifndef CLASS_PIN_H +#define CLASS_PIN_H + +#include + + +#define TARGET_PIN_RADIUS 12 // Circle diameter drawn at the active end of pins + +/** + * The component library pin object electrical types used in ERC tests. + */ +enum ElectricPinType { + PIN_INPUT, + PIN_OUTPUT, + PIN_BIDI, + PIN_TRISTATE, + PIN_PASSIVE, + PIN_UNSPECIFIED, + PIN_POWER_IN, + PIN_POWER_OUT, + PIN_OPENCOLLECTOR, + PIN_OPENEMITTER, + PIN_NC, /* No connect */ + PIN_NMAX /* End of List (no used as pin type) */ +}; + + +/* Pin visibility flag bit. */ +#define PIN_INVISIBLE 1 /* Set makes pin invisible */ + + +/** + * The component library pin object drawing shapes. + */ +enum DrawPinShape { + NONE = 0, + INVERT = 1, + CLOCK = 2, + LOWLEVEL_IN = 4, + LOWLEVEL_OUT = 8, + CLOCK_FALL = 0x10, /* this is common form for inverted clock in Eastern Block */ + NONLOGIC = 0x20 +}; + + +/** + * The component library pin object orientations. + */ +enum DrawPinOrient { + PIN_RIGHT = 'R', + PIN_LEFT = 'L', + PIN_UP = 'U', + PIN_DOWN = 'D' +}; + +enum LibPinDrawFlags { + PIN_DRAW_TEXTS = 1, + PIN_DRAW_DANGLING = 2, // Draw this pin with a 'dangling' indicator + PIN_DANGLING_HIDDEN = 4, // Draw (only!) the dangling indicator if the pin is hidden +}; + + +class LIB_PIN : public LIB_ITEM +{ + wxPoint m_position; ///< Position of the pin. + int m_length; ///< Length of the pin. + int m_orientation; ///< Pin orientation (Up, Down, Left, Right) + int m_shape; ///< Bitwise ORed of pin shapes (see enum DrawPinShape) + int m_width; ///< Line width of the pin. + int m_type; ///< Electrical type of the pin. See enum ElectricPinType. + int m_attributes; ///< Set bit 0 to indicate pin is invisible. + wxString m_name; + long m_number; ///< Pin number defined as 4 ASCII characters like "12", "anod", + ///< "G6", or "12". It is stored as "12\0\0" and does not + ///< depend on endian type. + int m_numTextSize; + int m_nameTextSize; ///< Pin num and Pin name sizes + + /** + * Draw a pin, with or without the pin texts + * + * @param aPanel DrawPanel to use (can be null) mainly used for clipping purposes. + * @param aDC Device Context (can be null) + * @param aOffset Offset to draw + * @param aColor -1 to use the normal body item color, or use this color if >= 0 + * @param aDrawMode GR_OR, GR_XOR, ... + * @param aData = used here as uintptr_t containing bitwise OR'd flags: + * PIN_DRAW_TEXTS, -- false to draw only pin shape, useful for fast mode + * PIN_DRAW_DANGLING, -- true to draw the pin with its target + * PIN_DANGLING_HIDDEN -- draw the target even if the pin is hidden + * @param aTransform Transform Matrix (rotation, mirror ..) + */ + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + +public: + LIB_PIN( LIB_PART* aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_PIN() { } + + wxString GetClass() const + { + return wxT( "LIB_PIN" ); + } + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // virtual override +#endif + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint &aPosRef, int aThreshold, const TRANSFORM& aTransform ) const; + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + /** + * Function PinEndPoint + * + * @return The pin end position for a component in the normal orientation. + */ + wxPoint PinEndPoint() const; + + /** + * Function PinDrawOrient + * returns the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), + * according to its orientation and the matrix transform (rot, mirror) \a aTransform + * + * @param aTransform Transform matrix + */ + int PinDrawOrient( const TRANSFORM& aTransform ) const; + + /** + * Fill a string buffer with pin number. + * + * Pin numbers are coded as a long or 4 ASCII characters. Used to print + * or draw the pin number. + * + * @param aStringBuffer - the wxString to store the pin num as an unicode string + */ + void PinStringNum( wxString& aStringBuffer ) const; + + long GetNumber() const { return m_number; } + + wxString GetNumberString() const { return PinStringNum( m_number ); } + + /** + * Function PinStringNum (static function) + * Pin num is coded as a long or 4 ascii chars + * @param aPinNum = a long containing a pin num + * @return aStringBuffer = the wxString to store the pin num as an + * unicode string + */ + static wxString PinStringNum( long aPinNum ); + + /** + * Function SetPinNumFromString + * fill the pin number buffer with \a aBuffer. + */ + void SetPinNumFromString( wxString& aBuffer ); + + wxString GetName() const { return m_name; } + + /** + * Set the pin name. + * + * This will also all of the pin names marked by EnableEditMode(). + * + * @param aName New pin name. + */ + void SetName( const wxString& aName ); + + /** + * Set the \a aSize of the pin name text. + * + * This will also update the text size of the name of the pins marked + * by EnableEditMode(). + * + * @param aSize The text size of the pin name in schematic units ( mils ). + */ + void SetNameTextSize( int aSize ); + + int GetNameTextSize() const { return m_nameTextSize; } + + /** + * Set the pin number. + * + * Others pin numbers marked by EnableEditMode() are not modified + * because each pin has its own number + * @param aNumber New pin number. + */ + void SetNumber( const wxString& aNumber ); + + /** + * Set the size of the pin number text. + * + * This will also update the text size of the number of the pins marked + * by EnableEditMode(). + * + * @param aSize The text size of the pin number in schematic units ( mils ). + */ + void SetNumberTextSize( int aSize ); + + int GetNumberTextSize() const { return m_numTextSize; } + + int GetOrientation() const { return m_orientation; } + + /** + * Set orientation on the pin. + * + * This will also update the orientation of the pins marked by EnableEditMode(). + * + * @param aOrientation - The orientation of the pin. + */ + void SetOrientation( int aOrientation ); + + void Rotate(); + + int GetShape() const { return m_shape; } + + /** + * Set the shape of the pin to \a aShape. + * + * This will also update the draw style of the pins marked by EnableEditMode(). + * + * @param aShape - The draw shape of the pin. See enum DrawPinShape. + */ + void SetShape( int aShape ); + + /** + * Get the electrical type of the pin. + * + * @return The electrical type of the pin (see enun ElectricPinType for values). + */ + int GetType() const { return m_type; } + + /** + * return a string giving the electrical type of a pin. + * Can be used when a known, not translated name is needed (for instance in net lists) + * @param aType is the electrical type (see enum ElectricPinType ) + * @return The electrical name for a pin type (see enun MsgPinElectricType for names). + */ + static const wxString GetCanonicalElectricalTypeName( unsigned aType ); + + /** + * return a string giving the electrical type of the pin. + * Can be used when a known, not translated name is needed (for instance in net lists) + * @return The canonical electrical name of the pin. + */ + wxString const GetCanonicalElectricalTypeName() const + { + return GetCanonicalElectricalTypeName( m_type ); + } + + /** + * return a translated string for messages giving the electrical type of a pin. + * @param aType is the electrical type (see enum ElectricPinType ) + * @return The electrical name of the pin (see enun MsgPinElectricType for names). + */ + static const wxString GetElectricalTypeName( unsigned aType ); + + /** + * return a translated string for messages giving the electrical type of the pin. + * @return The electrical name of the pin. + */ + wxString const GetElectricalTypeName() const + { + return GetElectricalTypeName( m_type ); + } + + /** + * Set the electrical type of the pin. + * + * This will also update the electrical type of the pins marked by + * EnableEditMode(). + * + * @param aType - The electrical type of the pin(see enun ElectricPinType for values). + */ + void SetType( int aType ); + + /** + * Set the pin length. + * + * This will also update the length of the pins marked by EnableEditMode(). + * + * @param aLength - The length of the pin in mils. + */ + void SetLength( int aLength ); + + int GetLength() { return m_length; } + + /** + * Set the pin part number. + * + * If the pin is changed from not common to common to all parts, any + * linked pins will be removed from the parent component. + * + * @param aPart - Number of the part the pin belongs to. Set to zero to + * make pin common to all parts in a multi-part component. + */ + void SetPartNumber( int aPart ); + + /** Get the pin part number. */ + int GetPartNumber() const { return m_Unit; } + + /** + * Set the body style (conversion) of the pin. + * + * If the pin is changed from not common to common to all body styles, any + * linked pins will be removed from the parent component. + * + * @param aConversion - Body style of the pin. Set to zero to make pin + * common to all body styles. + */ + void SetConversion( int aConversion ); + + /** + * Set or clear the visibility flag for the pin. + * + * This will also update the visibility of the pins marked by + * EnableEditMode(). + * + * @param aVisible - True to make the pin visible or false to hide the pin. + */ + void SetVisible( bool aVisible ); + + /** + * Enable or clear pin editing mode. + * + * The pin editing mode marks or unmarks all pins common to this + * pin object for further editing. If any of the pin modification + * methods are called after enabling the editing mode, all pins + * marked for editing will have the same attribute changed. The + * only case were this is not true making this pin common to all + * parts or body styles in the component. See SetCommonToAllParts() + * and SetCommonToAllBodyStyles() for more information. + * + * @param aEnable True marks all common pins for editing mode. False + * clears the editing mode. + * @param aEditPinByPin Enables the edit pin by pin mode. + */ + void EnableEditMode( bool aEnable, bool aEditPinByPin = false ); + + /** + * Return the visibility status of the draw object. + * + * @return True if draw object is visible otherwise false. + */ + bool IsVisible() const { return ( m_attributes & PIN_INVISIBLE ) == 0; } + + /** + * Return whether this pin forms an implicit power connection: i.e., is hidden + * and of type POWER_IN. + */ + bool IsPowerConnection() const { return !IsVisible() && GetType() == PIN_POWER_IN; } + + int GetPenSize() const; + + /** + * Function DrawPinSymbol + * Draw the pin symbol without text. + * If \a aColor != 0, draw with \a aColor, else with the normal pin color. + */ + void DrawPinSymbol( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + int aOrientation, GR_DRAWMODE aDrawMode, + EDA_COLOR_T aColor = UNSPECIFIED_COLOR, + bool aDrawDangling = true, + bool aOnlyTarget = false ); + + /** + * Function DrawPinTexts + * puts the pin number and pin text info, given the pin line coordinates. + * The line must be vertical or horizontal. + * If DrawPinName == false the pin name is not printed. + * If DrawPinNum = false the pin number is not printed. + * If TextInside then the text is been put inside,otherwise all is drawn outside. + * Pin Name: substring between '~' is negated + * DrawMode = GR_OR, XOR ... + */ + void DrawPinTexts( EDA_DRAW_PANEL* aPanel, wxDC* aDC, wxPoint& aPosition, + int aOrientation, int TextInside, bool DrawPinNum, bool DrawPinName, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode ); + + /** + * Function PlotPinTexts + * plots the pin number and pin text info, given the pin line coordinates. + * Same as DrawPinTexts((), but output is the plotter + * The line must be vertical or horizontal. + * If TextInside then the text is been put inside (moving from x1, y1 in + * the opposite direction to x2,y2), otherwise all is drawn outside. + */ + void PlotPinTexts( PLOTTER *aPlotter, + wxPoint& aPosition, + int aOrientation, + int aTextInside, + bool aDrawPinNum, + bool aDrawPinName, + int aWidth ); + + void PlotSymbol( PLOTTER* aPlotter, const wxPoint& aPosition, int aOrientation ); + + /** + * Get a list of pin orientation names. + * + * @return List of valid pin orientation names. + */ + static wxArrayString GetOrientationNames(); + + /** + * Get a list of pin orientation bitmaps for menus and dialogs. + * + * @return List of valid pin orientation bitmaps symbols in .xpm format + */ + static const BITMAP_DEF* GetOrientationSymbols(); + + /** + * Get the orientation code by index used to set the pin orientation. + * + * @param aIndex - The index of the orientation code to look up. + * @return Orientation code if index is valid. Returns right + * orientation on index error. + */ + static int GetOrientationCode( int aIndex ); + + /** + * Get the index of the orientation code. + * + * @param aCode - The orientation code to look up. + * @return The index of the orientation code if found. Otherwise, + * return wxNOT_FOUND. + */ + static int GetOrientationCodeIndex( int aCode ); + + /** + * Get a list of pin draw style names. + * + * @return List of valid pin draw style names. + */ + static wxArrayString GetStyleNames(); + + /** + * Get a list of pin styles bitmaps for menus and dialogs. + * + * @return List of valid pin electrical type bitmaps symbols in .xpm format. + */ + static const BITMAP_DEF* GetStyleSymbols(); + + /** + * Get the pin draw style code by index used to set the pin draw style. + * + * @param aIndex - The index of the pin draw style code to look up. + * @return Pin draw style code if index is valid. Returns NONE + * style on index error. + */ + static int GetStyleCode( int aIndex ); + + /** + * Get the index of the pin draw style code. + * + * @param aCode - The pin draw style code to look up. + * @return The index of the pin draw style code if found. Otherwise, + * return wxNOT_FOUND. + */ + static int GetStyleCodeIndex( int aCode ); + + /** + * Get a list of pin electrical type names. + * + * @return List of valid pin electrical type names. + */ + static wxArrayString GetElectricalTypeNames(); + + /** + * Get a list of pin electrical bitmaps for menus and dialogs. + * + * @return List of valid pin electrical type bitmaps symbols in .xpm format + */ + static const BITMAP_DEF* GetElectricalTypeSymbols(); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_position; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_width; } + + void SetWidth( int aWidth ); + + BITMAP_DEF GetMenuImage() const; + + wxString GetSelectMenuText() const; + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The pin specific sort order is as follows: + * - Pin number. + * - Pin name, case insensitive compare. + * - Pin horizontal (X) position. + * - Pin vertical (Y) position. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // CLASS_PIN_H diff --git a/eeschema/lib_polyline.cpp b/eeschema/lib_polyline.cpp new file mode 100644 index 00000000..826adca0 --- /dev/null +++ b/eeschema/lib_polyline.cpp @@ -0,0 +1,562 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_polyline.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +LIB_POLYLINE::LIB_POLYLINE( LIB_PART* aParent ) : + LIB_ITEM( LIB_POLYLINE_T, aParent ) +{ + m_Fill = NO_FILL; + m_Width = 0; + m_isFillable = true; + m_typeName = _( "PolyLine" ); + m_ModifyIndex = 0; +} + + +bool LIB_POLYLINE::Save( OUTPUTFORMATTER& aFormatter ) +{ + int ccount = GetCornerCount(); + + aFormatter.Print( 0, "P %d %d %d %d", ccount, m_Unit, m_Convert, m_Width ); + + for( unsigned i = 0; i < GetCornerCount(); i++ ) + { + aFormatter.Print( 0, " %d %d", m_PolyPoints[i].x, m_PolyPoints[i].y ); + } + + aFormatter.Print( 0, " %c\n", fill_tab[m_Fill] ); + + return true; +} + + +bool LIB_POLYLINE::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + char* p; + int i, ccount = 0; + wxPoint pt; + char* line = (char*) aLineReader; + + i = sscanf( line + 2, "%d %d %d %d", &ccount, &m_Unit, &m_Convert, &m_Width ); + + m_Fill = NO_FILL; + + if( i < 4 ) + { + aErrorMsg.Printf( _( "Polyline only had %d parameters of the required 4" ), i ); + return false; + } + + if( ccount <= 0 ) + { + aErrorMsg.Printf( _( "Polyline count parameter %d is invalid" ), ccount ); + return false; + } + + strtok( line + 2, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); // Skip field + strtok( NULL, " \t\n" ); + + for( i = 0; i < ccount; i++ ) + { + p = strtok( NULL, " \t\n" ); + + if( p == NULL || sscanf( p, "%d", &pt.x ) != 1 ) + { + aErrorMsg.Printf( _( "Polyline point %d X position not defined" ), i ); + return false; + } + + p = strtok( NULL, " \t\n" ); + + if( p == NULL || sscanf( p, "%d", &pt.y ) != 1 ) + { + aErrorMsg.Printf( _( "Polyline point %d Y position not defined" ), i ); + return false; + } + + AddPoint( pt ); + } + + if( ( p = strtok( NULL, " \t\n" ) ) != NULL ) + { + if( p[0] == 'F' ) + m_Fill = FILLED_SHAPE; + + if( p[0] == 'f' ) + m_Fill = FILLED_WITH_BG_BODYCOLOR; + } + + return true; +} + + +EDA_ITEM* LIB_POLYLINE::Clone() const +{ + return new LIB_POLYLINE( *this ); +} + + +int LIB_POLYLINE::compare( const LIB_ITEM& aOther ) const +{ + wxASSERT( aOther.Type() == LIB_POLYLINE_T ); + + const LIB_POLYLINE* tmp = (LIB_POLYLINE*) &aOther; + + if( m_PolyPoints.size() != tmp->m_PolyPoints.size() ) + return m_PolyPoints.size() - tmp->m_PolyPoints.size(); + + for( size_t i = 0; i < m_PolyPoints.size(); i++ ) + { + if( m_PolyPoints[i].x != tmp->m_PolyPoints[i].x ) + return m_PolyPoints[i].x - tmp->m_PolyPoints[i].x; + + if( m_PolyPoints[i].y != tmp->m_PolyPoints[i].y ) + return m_PolyPoints[i].y - tmp->m_PolyPoints[i].y; + } + + return 0; +} + + +void LIB_POLYLINE::SetOffset( const wxPoint& aOffset ) +{ + for( size_t i = 0; i < m_PolyPoints.size(); i++ ) + m_PolyPoints[i] += aOffset; +} + + +bool LIB_POLYLINE::Inside( EDA_RECT& aRect ) const +{ + for( size_t i = 0; i < m_PolyPoints.size(); i++ ) + { + if( aRect.Contains( m_PolyPoints[i].x, -m_PolyPoints[i].y ) ) + return true; + } + + return false; +} + + +void LIB_POLYLINE::Move( const wxPoint& aPosition ) +{ + SetOffset( aPosition - m_PolyPoints[0] ); +} + + +void LIB_POLYLINE::MirrorHorizontal( const wxPoint& aCenter ) +{ + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_PolyPoints[i].x -= aCenter.x; + m_PolyPoints[i].x *= -1; + m_PolyPoints[i].x += aCenter.x; + } +} + +void LIB_POLYLINE::MirrorVertical( const wxPoint& aCenter ) +{ + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + m_PolyPoints[i].y -= aCenter.y; + m_PolyPoints[i].y *= -1; + m_PolyPoints[i].y += aCenter.y; + } +} + +void LIB_POLYLINE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + + size_t i, imax = m_PolyPoints.size(); + + for( i = 0; i < imax; i++ ) + { + RotatePoint( &m_PolyPoints[i], aCenter, rot_angle ); + } +} + + +void LIB_POLYLINE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + static std::vector< wxPoint > cornerList; + cornerList.clear(); + + for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) + { + wxPoint pos = m_PolyPoints[ii]; + pos = aTransform.TransformCoordinate( pos ) + aOffset; + cornerList.push_back( pos ); + } + + if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR ) + { + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + aPlotter->PlotPoly( cornerList, FILLED_WITH_BG_BODYCOLOR, 0 ); + } + + bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR; + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + aPlotter->PlotPoly( cornerList, already_filled ? NO_FILL : m_Fill, GetPenSize() ); +} + + +void LIB_POLYLINE::AddPoint( const wxPoint& point ) +{ + m_PolyPoints.push_back( point ); +} + + +int LIB_POLYLINE::GetPenSize() const +{ + return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width; +} + + +void LIB_POLYLINE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + wxPoint pos1; + EDA_COLOR_T color = GetLayerColor( LAYER_DEVICE ); + wxPoint* buffer = NULL; + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + buffer = new wxPoint[ m_PolyPoints.size() ]; + + for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) + { + buffer[ii] = aTransform.TransformCoordinate( m_PolyPoints[ii] ) + aOffset; + } + + FILL_T fill = aData ? NO_FILL : m_Fill; + + if( aColor >= 0 ) + fill = NO_FILL; + + GRSetDrawMode( aDC, aDrawMode ); + + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; + if( fill == FILLED_WITH_BG_BODYCOLOR ) + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), + (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), + GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + else if( fill == FILLED_SHAPE ) + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), + color, color ); + else + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 0, GetPenSize(), + color, color ); + + delete[] buffer; + + /* Set to one (1) to draw bounding box around polyline to validate + * bounding box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +bool LIB_POLYLINE::HitTest( const wxPoint& aPosition ) const +{ + int mindist = GetPenSize() / 2; + + // Have a minimal tolerance for hit test + if( mindist < MINIMUM_SELECTION_DISTANCE ) + mindist = MINIMUM_SELECTION_DISTANCE; + + return HitTest( aPosition, mindist, DefaultTransform ); +} + + +bool LIB_POLYLINE::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + wxPoint start, end; + + if( aThreshold < 0 ) + aThreshold = GetPenSize() / 2; + + for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) + { + start = aTransform.TransformCoordinate( m_PolyPoints[ii - 1] ); + end = aTransform.TransformCoordinate( m_PolyPoints[ii] ); + + if( TestSegmentHit( aPosition, start, end, aThreshold ) ) + return true; + } + + return false; +} + + +const EDA_RECT LIB_POLYLINE::GetBoundingBox() const +{ + EDA_RECT rect; + int xmin, xmax, ymin, ymax; + + xmin = xmax = m_PolyPoints[0].x; + ymin = ymax = m_PolyPoints[0].y; + + for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) + { + xmin = std::min( xmin, m_PolyPoints[ii].x ); + xmax = std::max( xmax, m_PolyPoints[ii].x ); + ymin = std::min( ymin, m_PolyPoints[ii].y ); + ymax = std::max( ymax, m_PolyPoints[ii].y ); + } + + rect.SetOrigin( xmin, ymin ); + rect.SetEnd( xmax, ymax ); + rect.Inflate( ( GetPenSize()+1 ) / 2 ); + + rect.RevertYAxis(); + + return rect; +} + + +void LIB_POLYLINE::DeleteSegment( const wxPoint aPosition ) +{ + // First segment is kept, only its end point is changed + while( GetCornerCount() > 2 ) + { + m_PolyPoints.pop_back(); + + if( m_PolyPoints[ GetCornerCount() - 1 ] != aPosition ) + { + m_PolyPoints[ GetCornerCount() - 1 ] = aPosition; + break; + } + } +} + + +void LIB_POLYLINE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + EDA_RECT bBox = GetBoundingBox(); + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Width, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); + + msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, + bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y ); + + aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) ); +} + + +wxString LIB_POLYLINE::GetSelectMenuText() const +{ + return wxString::Format( _( "Polyline at (%s, %s) with %d points" ), + GetChars( CoordinateToString( m_PolyPoints[0].x ) ), + GetChars( CoordinateToString( m_PolyPoints[0].y ) ), + int( m_PolyPoints.size() ) ); +} + + +void LIB_POLYLINE::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Invalid edit mode for LIB_POLYLINE object." ) ); + + if( aEditMode == IS_NEW ) + { + m_PolyPoints.push_back( aPosition ); // Start point of first segment. + m_PolyPoints.push_back( aPosition ); // End point of first segment. + } + else if( aEditMode == IS_RESIZED ) + { + // Drag one edge point of the polyline + // Find the nearest edge point to be dragged + wxPoint startPoint = m_PolyPoints[0]; + + // Begin with the first list point as nearest point + int index = 0; + m_ModifyIndex = 0; + m_initialPos = startPoint; + + // First distance is the current minimum distance + int distanceMin = (aPosition - startPoint).x * (aPosition - startPoint).x + + (aPosition - startPoint).y * (aPosition - startPoint).y; + + wxPoint prevPoint = startPoint; + + // Find the right index of the point to be dragged + BOOST_FOREACH( wxPoint point, m_PolyPoints ) + { + int distancePoint = (aPosition - point).x * (aPosition - point).x + + (aPosition - point).y * (aPosition - point).y; + + if( distancePoint < distanceMin ) + { + // Save point. + m_initialPos = point; + m_ModifyIndex = index; + distanceMin = distancePoint; + } + + // check middle of an edge + wxPoint offset = ( aPosition + aPosition - point - prevPoint ); + distancePoint = ( offset.x * offset.x + offset.y * offset.y ) / 4 + 1; + + if( distancePoint < distanceMin ) + { + // Save point. + m_initialPos = point; + m_ModifyIndex = -index; // negative indicates new vertex is to be inserted + distanceMin = distancePoint; + } + + prevPoint = point; + index++; + } + + SetEraseLastDrawItem(); + } + else if( aEditMode == IS_MOVED ) + { + m_initialCursorPos = aPosition; + m_initialPos = m_PolyPoints[0]; + SetEraseLastDrawItem(); + } + + m_Flags = aEditMode; +} + + +bool LIB_POLYLINE::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). LIB_POLYLINE is not being edited." ) ); + + if( m_Flags == IS_NEW ) + { + // do not add zero length segments + if( m_PolyPoints[m_PolyPoints.size() - 2] != m_PolyPoints.back() ) + m_PolyPoints.push_back( aPosition ); + + return true; + } + + return false; +} + + +void LIB_POLYLINE::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Bad call to EndEdit(). LIB_POLYLINE is not being edited." ) ); + + // do not include last point twice + if( m_Flags == IS_NEW && 2 < m_PolyPoints.size() ) + { + if( m_PolyPoints[ m_PolyPoints.size() - 2 ] == m_PolyPoints.back() ) + m_PolyPoints.pop_back(); + } + + if( (m_Flags == IS_RESIZED) && (m_PolyPoints.size() > 2) ) // do not delete last two points... keep it alive + { + if( ( m_ModifyIndex > 0 && m_PolyPoints[ m_ModifyIndex ] == + m_PolyPoints[ m_ModifyIndex - 1 ] ) + || ( m_ModifyIndex < (int) m_PolyPoints.size() - 1 + && m_PolyPoints[ m_ModifyIndex ] == m_PolyPoints[ m_ModifyIndex + 1 ] ) ) + { + m_PolyPoints.erase( m_PolyPoints.begin() + m_ModifyIndex ); // delete a point on this + } + } + + m_Flags = 0; + SetEraseLastDrawItem( false ); +} + + +void LIB_POLYLINE::calcEdit( const wxPoint& aPosition ) +{ + if( m_Flags == IS_NEW ) + { + m_PolyPoints[ GetCornerCount() - 1 ] = aPosition; + SetEraseLastDrawItem(); + } + else if( m_Flags == IS_RESIZED ) + { + if( m_ModifyIndex < 0 ) // negative indicates new vertex is to be inserted + { + m_ModifyIndex = -m_ModifyIndex; + m_PolyPoints.insert( m_PolyPoints.begin() + m_ModifyIndex, aPosition ); + } + + m_PolyPoints[ m_ModifyIndex ] = aPosition; + } + else if( m_Flags == IS_MOVED ) + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} diff --git a/eeschema/lib_polyline.h b/eeschema/lib_polyline.h new file mode 100644 index 00000000..88e397f1 --- /dev/null +++ b/eeschema/lib_polyline.h @@ -0,0 +1,133 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_polyline.h + */ + +#ifndef _LIB_POLYLINE_H_ +#define _LIB_POLYLINE_H_ + +#include + + +class LIB_POLYLINE : public LIB_ITEM +{ + int m_Width; // Line width + std::vector m_PolyPoints; // list of points (>= 2) + + int m_ModifyIndex; // Index of the polyline point to modify + + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + void calcEdit( const wxPoint& aPosition ); + +public: + LIB_POLYLINE( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_POLYLINE() { } + + wxString GetClass() const + { + return wxT( "LIB_POLYLINE" ); + } + + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + void AddPoint( const wxPoint& aPoint ); + + /** + * Delete the segment at \a aPosition. + */ + void DeleteSegment( const wxPoint aPosition ); + + /** + * @return the number of corners + */ + unsigned GetCornerCount() const { return m_PolyPoints.size(); } + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + int GetPenSize( ) const; + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_PolyPoints[0]; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Width; } + + void SetWidth( int aWidth ) { m_Width = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_polygon_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The sort order for specific to each polyline segment point is as follows: + * - Line segment point horizontal (X) position. + * - Line segment point vertical (Y) position. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_POLYLINE_H_ diff --git a/eeschema/lib_rectangle.cpp b/eeschema/lib_rectangle.cpp new file mode 100644 index 00000000..74a19876 --- /dev/null +++ b/eeschema/lib_rectangle.cpp @@ -0,0 +1,434 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_rectangle.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +LIB_RECTANGLE::LIB_RECTANGLE( LIB_PART* aParent ) : + LIB_ITEM( LIB_RECTANGLE_T, aParent ) +{ + m_Width = 0; + m_Fill = NO_FILL; + m_isFillable = true; + m_typeName = _( "Rectangle" ); + m_isHeightLocked = false; + m_isWidthLocked = false; + m_isStartPointSelected = false; +} + + +bool LIB_RECTANGLE::Save( OUTPUTFORMATTER& aFormatter ) +{ + aFormatter.Print( 0, "S %d %d %d %d %d %d %d %c\n", m_Pos.x, m_Pos.y, + m_End.x, m_End.y, m_Unit, m_Convert, m_Width, fill_tab[m_Fill] ); + + return true; +} + + +bool LIB_RECTANGLE::Load( LINE_READER& aLineReader, wxString& aErrorMsg ) +{ + int cnt; + char tmp[256] = ""; + char* line = (char*)aLineReader; + + cnt = sscanf( line + 2, "%d %d %d %d %d %d %d %255s", &m_Pos.x, &m_Pos.y, + &m_End.x, &m_End.y, &m_Unit, &m_Convert, &m_Width, tmp ); + + if( cnt < 7 ) + { + aErrorMsg.Printf( _( "Rectangle only had %d parameters of the required 7" ), cnt ); + return false; + } + + if( tmp[0] == 'F' ) + m_Fill = FILLED_SHAPE; + + if( tmp[0] == 'f' ) + m_Fill = FILLED_WITH_BG_BODYCOLOR; + + return true; +} + + +EDA_ITEM* LIB_RECTANGLE::Clone() const +{ + return new LIB_RECTANGLE( *this ); +} + + +int LIB_RECTANGLE::compare( const LIB_ITEM& aOther ) const +{ + wxASSERT( aOther.Type() == LIB_RECTANGLE_T ); + + const LIB_RECTANGLE* tmp = ( LIB_RECTANGLE* ) &aOther; + + if( m_Pos.x != tmp->m_Pos.x ) + return m_Pos.x - tmp->m_Pos.x; + + if( m_Pos.y != tmp->m_Pos.y ) + return m_Pos.y - tmp->m_Pos.y; + + if( m_End.x != tmp->m_End.x ) + return m_End.x - tmp->m_End.x; + + if( m_End.y != tmp->m_End.y ) + return m_End.y - tmp->m_End.y; + + return 0; +} + + +void LIB_RECTANGLE::SetOffset( const wxPoint& aOffset ) +{ + m_Pos += aOffset; + m_End += aOffset; +} + + +bool LIB_RECTANGLE::Inside( EDA_RECT& aRect ) const +{ + return aRect.Contains( m_Pos.x, -m_Pos.y ) || aRect.Contains( m_End.x, -m_End.y ); +} + + +void LIB_RECTANGLE::Move( const wxPoint& aPosition ) +{ + wxPoint size = m_End - m_Pos; + m_Pos = aPosition; + m_End = aPosition + size; +} + + +void LIB_RECTANGLE::MirrorHorizontal( const wxPoint& aCenter ) +{ + m_Pos.x -= aCenter.x; + m_Pos.x *= -1; + m_Pos.x += aCenter.x; + m_End.x -= aCenter.x; + m_End.x *= -1; + m_End.x += aCenter.x; +} + + +void LIB_RECTANGLE::MirrorVertical( const wxPoint& aCenter ) +{ + m_Pos.y -= aCenter.y; + m_Pos.y *= -1; + m_Pos.y += aCenter.y; + m_End.y -= aCenter.y; + m_End.y *= -1; + m_End.y += aCenter.y; +} + + +void LIB_RECTANGLE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + RotatePoint( &m_Pos, aCenter, rot_angle ); + RotatePoint( &m_End, aCenter, rot_angle ); +} + + +void LIB_RECTANGLE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ) +{ + wxASSERT( aPlotter != NULL ); + + wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; + wxPoint end = aTransform.TransformCoordinate( m_End ) + aOffset; + + if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR ) + { + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + aPlotter->Rect( pos, end, FILLED_WITH_BG_BODYCOLOR, 0 ); + } + + bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR; + aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) ); + aPlotter->Rect( pos, end, already_filled ? NO_FILL : m_Fill, GetPenSize() ); +} + + +int LIB_RECTANGLE::GetPenSize() const +{ + return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width; +} + + +void LIB_RECTANGLE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, + void* aData, const TRANSFORM& aTransform ) +{ + wxPoint pos1, pos2; + + EDA_COLOR_T color = GetLayerColor( LAYER_DEVICE ); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + pos1 = aTransform.TransformCoordinate( m_Pos ) + aOffset; + pos2 = aTransform.TransformCoordinate( m_End ) + aOffset; + + FILL_T fill = aData ? NO_FILL : m_Fill; + + if( aColor >= 0 ) + fill = NO_FILL; + + GRSetDrawMode( aDC, aDrawMode ); + + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; + if( fill == FILLED_WITH_BG_BODYCOLOR && !aData ) + GRFilledRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize( ), + (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), + GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); + else if( m_Fill == FILLED_SHAPE && !aData ) + GRFilledRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, + GetPenSize(), color, color ); + else + GRRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize(), color ); + + /* Set to one (1) to draw bounding box around rectangle to validate + * bounding box calculation. */ +#if 0 + EDA_RECT bBox = GetBoundingBox(); + bBox.RevertYAxis(); + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +void LIB_RECTANGLE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Width, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); +} + + +const EDA_RECT LIB_RECTANGLE::GetBoundingBox() const +{ + EDA_RECT rect; + + rect.SetOrigin( m_Pos ); + rect.SetEnd( m_End ); + rect.Inflate( ( GetPenSize()+1 ) / 2 ); + + rect.RevertYAxis(); + + return rect; +} + + +bool LIB_RECTANGLE::HitTest( const wxPoint& aPosition ) const +{ + int mindist = ( GetPenSize() / 2 ) + 1; + + // Have a minimal tolerance for hit test + if( mindist < MINIMUM_SELECTION_DISTANCE ) + mindist = MINIMUM_SELECTION_DISTANCE; + + return HitTest( aPosition, mindist, DefaultTransform ); +} + + +bool LIB_RECTANGLE::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + if( aThreshold < 0 ) + aThreshold = GetPenSize() / 2; + + wxPoint actualStart = aTransform.TransformCoordinate( m_Pos ); + wxPoint actualEnd = aTransform.TransformCoordinate( m_End ); + + // locate lower segment + wxPoint start, end; + + start = actualStart; + end.x = actualEnd.x; + end.y = actualStart.y; + + if( TestSegmentHit( aPosition, start, end, aThreshold ) ) + return true; + + // locate right segment + start.x = actualEnd.x; + end.y = actualEnd.y; + + if( TestSegmentHit( aPosition, start, end, aThreshold ) ) + return true; + + // locate upper segment + start.y = actualEnd.y; + end.x = actualStart.x; + + if( TestSegmentHit( aPosition, start, end, aThreshold ) ) + return true; + + // locate left segment + start = actualStart; + end.x = actualStart.x; + end.y = actualEnd.y; + + if( TestSegmentHit( aPosition, start, end, aThreshold ) ) + return true; + + return false; +} + + +wxString LIB_RECTANGLE::GetSelectMenuText() const +{ + return wxString::Format( _( "Rectangle from (%s, %s) to (%s, %s)" ), + GetChars( CoordinateToString( m_Pos.x ) ), + GetChars( CoordinateToString( m_Pos.y ) ), + GetChars( CoordinateToString( m_End.x ) ), + GetChars( CoordinateToString( m_End.y ) ) ); +} + + +void LIB_RECTANGLE::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Invalid edit mode for LIB_RECTANGLE object." ) ); + + if( aEditMode == IS_NEW ) + { + m_Pos = m_End = aPosition; + } + else if( aEditMode == IS_RESIZED ) + { + m_isStartPointSelected = abs( m_Pos.x - aPosition.x ) < MINIMUM_SELECTION_DISTANCE + || abs( m_Pos.y - aPosition.y ) < MINIMUM_SELECTION_DISTANCE; + + if( m_isStartPointSelected ) + { + m_isWidthLocked = abs( m_Pos.x - aPosition.x ) >= MINIMUM_SELECTION_DISTANCE; + m_isHeightLocked = abs( m_Pos.y - aPosition.y ) >= MINIMUM_SELECTION_DISTANCE; + } + else + { + m_isWidthLocked = abs( m_End.x - aPosition.x ) >= MINIMUM_SELECTION_DISTANCE; + m_isHeightLocked = abs( m_End.y - aPosition.y ) >= MINIMUM_SELECTION_DISTANCE; + } + + SetEraseLastDrawItem(); + } + else if( aEditMode == IS_MOVED ) + { + m_initialPos = m_Pos; + m_initialCursorPos = aPosition; + SetEraseLastDrawItem(); + } + + m_Flags = aEditMode; +} + + +bool LIB_RECTANGLE::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). LIB_RECTANGLE is not being edited." ) ); + + return false; +} + + +void LIB_RECTANGLE::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, + wxT( "Bad call to EndEdit(). LIB_RECTANGLE is not being edited." ) ); + + m_Flags = 0; + m_isHeightLocked = false; + m_isWidthLocked = false; + SetEraseLastDrawItem( false ); +} + + +void LIB_RECTANGLE::calcEdit( const wxPoint& aPosition ) +{ + if( m_Flags == IS_NEW ) + { + m_End = aPosition; + SetEraseLastDrawItem(); + } + else if( m_Flags == IS_RESIZED ) + { + if( m_isHeightLocked ) + { + if( m_isStartPointSelected ) + m_Pos.x = aPosition.x; + else + m_End.x = aPosition.x; + } + else if( m_isWidthLocked ) + { + if( m_isStartPointSelected ) + m_Pos.y = aPosition.y; + else + m_End.y = aPosition.y; + } + else + { + if( m_isStartPointSelected ) + m_Pos = aPosition; + else + m_End = aPosition; + } + } + else if( m_Flags == IS_MOVED ) + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} diff --git a/eeschema/lib_rectangle.h b/eeschema/lib_rectangle.h new file mode 100644 index 00000000..6df93c9c --- /dev/null +++ b/eeschema/lib_rectangle.h @@ -0,0 +1,126 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_rectangle.h + */ + +#ifndef _LIB_RECTANGLE_H_ +#define _LIB_RECTANGLE_H_ + +#include + + +class LIB_RECTANGLE : public LIB_ITEM +{ + wxPoint m_End; // Rectangle end point. + wxPoint m_Pos; // Rectangle start point. + int m_Width; // Line width + bool m_isWidthLocked; // Flag: Keep width locked + bool m_isHeightLocked; // Flag: Keep height locked + bool m_isStartPointSelected; // Flag: is the upper left edge selected? + + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + void calcEdit( const wxPoint& aPosition ); + +public: + LIB_RECTANGLE( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_RECTANGLE() { } + + wxString GetClass() const + { + return wxT( "LIB_RECTANGLE" ); + } + + void SetEndPosition( const wxPoint& aPosition ) { m_End = aPosition; } + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint &aPosRef, int aThreshold, const TRANSFORM& aTransform ) const; + + int GetPenSize( ) const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_Pos; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Width; } + + void SetWidth( int aWidth ) { m_Width = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_rectangle_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The rectangle specific sort order is as follows: + * - Rectangle horizontal (X) start position. + * - Rectangle vertical (Y) start position. + * - Rectangle horizontal (X) end position. + * - Rectangle vertical (Y) end position. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_RECTANGLE_H_ diff --git a/eeschema/lib_text.cpp b/eeschema/lib_text.cpp new file mode 100644 index 00000000..be8ad784 --- /dev/null +++ b/eeschema/lib_text.cpp @@ -0,0 +1,559 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_text.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +LIB_TEXT::LIB_TEXT( LIB_PART * aParent ) : + LIB_ITEM( LIB_TEXT_T, aParent ), + EDA_TEXT() +{ + m_Size = wxSize( 50, 50 ); + m_typeName = _( "Text" ); + m_rotate = false; + m_updateText = false; +} + + +bool LIB_TEXT::Save( OUTPUTFORMATTER& aFormatter ) +{ + wxString text = m_Text; + + if( text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) ) + { + // convert double quote to similar-looking two apostrophes + text.Replace( wxT( "\"" ), wxT( "''" ) ); + text = wxT( "\"" ) + text + wxT( "\"" ); + } + else + { + // Spaces are not allowed in text because it is not double quoted: + // changed to '~' + text.Replace( wxT( " " ), wxT( "~" ) ); + } + + aFormatter.Print( 0, "T %g %d %d %d %d %d %d %s", GetOrientation(), m_Pos.x, m_Pos.y, + m_Size.x, m_Attributs, m_Unit, m_Convert, TO_UTF8( text ) ); + + aFormatter.Print( 0, " %s %d", m_Italic ? "Italic" : "Normal", ( m_Bold > 0 ) ? 1 : 0 ); + + char hjustify = 'C'; + + if( m_HJustify == GR_TEXT_HJUSTIFY_LEFT ) + hjustify = 'L'; + else if( m_HJustify == GR_TEXT_HJUSTIFY_RIGHT ) + hjustify = 'R'; + + char vjustify = 'C'; + + if( m_VJustify == GR_TEXT_VJUSTIFY_BOTTOM ) + vjustify = 'B'; + else if( m_VJustify == GR_TEXT_VJUSTIFY_TOP ) + vjustify = 'T'; + + aFormatter.Print( 0, " %c %c\n", hjustify, vjustify ); + + return true; +} + + +bool LIB_TEXT::Load( LINE_READER& aLineReader, wxString& errorMsg ) +{ + int cnt, thickness = 0; + char hjustify = 'C', vjustify = 'C'; + char buf[256]; + char tmp[256]; + char* line = (char*) aLineReader; + double angle; + + buf[0] = 0; + tmp[0] = 0; // For italic option, Not in old versions + + cnt = sscanf( line + 2, "%lf %d %d %d %d %d %d \"%[^\"]\" %255s %d %c %c", + &angle, &m_Pos.x, &m_Pos.y, &m_Size.x, &m_Attributs, + &m_Unit, &m_Convert, buf, tmp, &thickness, &hjustify, + &vjustify ); + + if( cnt >= 8 ) // if quoted loading failed, load as not quoted + { + m_Text = FROM_UTF8( buf ); + + // convert two apostrophes back to double quote + m_Text.Replace( wxT( "''" ), wxT( "\"" ) ); + } + else + { + cnt = sscanf( line + 2, "%lf %d %d %d %d %d %d %255s %255s %d %c %c", + &angle, &m_Pos.x, &m_Pos.y, &m_Size.x, &m_Attributs, + &m_Unit, &m_Convert, buf, tmp, &thickness, &hjustify, + &vjustify ); + + if( cnt < 8 ) + { + errorMsg.Printf( _( "Text only had %d parameters of the required 8" ), cnt ); + return false; + } + + /* Convert '~' to spaces (only if text is not quoted). */ + m_Text = FROM_UTF8( buf ); + m_Text.Replace( wxT( "~" ), wxT( " " ) ); + } + + SetOrientation( angle ); + + m_Size.y = m_Size.x; + + if( strnicmp( tmp, "Italic", 6 ) == 0 ) + m_Italic = true; + + if( thickness > 0 ) + { + m_Bold = true; + } + + switch( hjustify ) + { + case 'L': + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + break; + + case 'C': + m_HJustify = GR_TEXT_HJUSTIFY_CENTER; + break; + + case 'R': + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + break; + } + + switch( vjustify ) + { + case 'T': + m_VJustify = GR_TEXT_VJUSTIFY_TOP; + break; + + case 'C': + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 'B': + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + break; + } + + + return true; +} + + +bool LIB_TEXT::HitTest( const wxPoint& aPosition ) const +{ + return HitTest( aPosition, 0, DefaultTransform ); +} + + +bool LIB_TEXT::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const +{ + if( aThreshold < 0 ) + aThreshold = 0; + + EDA_TEXT tmp_text( *this ); + tmp_text.SetTextPosition( aTransform.TransformCoordinate( m_Pos ) ); + + /* The text orientation may need to be flipped if the + * transformation matrix causes xy axes to be flipped. + * this simple algo works only for schematic matrix (rot 90 or/and mirror) + */ + int t1 = ( aTransform.x1 != 0 ) ^ ( m_Orient != 0 ); + tmp_text.SetOrientation( t1 ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT ); + return tmp_text.TextHitTest( aPosition ); +} + + +EDA_ITEM* LIB_TEXT::Clone() const +{ + LIB_TEXT* newitem = new LIB_TEXT(NULL); + + newitem->m_Pos = m_Pos; + newitem->m_Orient = m_Orient; + newitem->m_Size = m_Size; + newitem->m_Attributs = m_Attributs; + newitem->m_Unit = m_Unit; + newitem->m_Convert = m_Convert; + newitem->m_Flags = m_Flags; + newitem->m_Text = m_Text; + newitem->m_Thickness = m_Thickness; + newitem->m_Italic = m_Italic; + newitem->m_Bold = m_Bold; + newitem->m_HJustify = m_HJustify; + newitem->m_VJustify = m_VJustify; + return newitem; +} + + +int LIB_TEXT::compare( const LIB_ITEM& other ) const +{ + wxASSERT( other.Type() == LIB_TEXT_T ); + + const LIB_TEXT* tmp = ( LIB_TEXT* ) &other; + + int result = m_Text.CmpNoCase( tmp->m_Text ); + + if( result != 0 ) + return result; + + if( m_Pos.x != tmp->m_Pos.x ) + return m_Pos.x - tmp->m_Pos.x; + + if( m_Pos.y != tmp->m_Pos.y ) + return m_Pos.y - tmp->m_Pos.y; + + if( m_Size.x != tmp->m_Size.x ) + return m_Size.x - tmp->m_Size.x; + + if( m_Size.y != tmp->m_Size.y ) + return m_Size.y - tmp->m_Size.y; + + return 0; +} + + +void LIB_TEXT::SetOffset( const wxPoint& aOffset ) +{ + m_Pos += aOffset; +} + + +bool LIB_TEXT::Inside( EDA_RECT& rect ) const +{ + /* + * FIXME: This should calculate the text size and justification and + * use rectangle intersect. + */ + return rect.Contains( m_Pos.x, -m_Pos.y ); +} + + +void LIB_TEXT::Move( const wxPoint& newPosition ) +{ + m_Pos = newPosition; +} + + +void LIB_TEXT::MirrorHorizontal( const wxPoint& center ) +{ + m_Pos.x -= center.x; + m_Pos.x *= -1; + m_Pos.x += center.x; +} + +void LIB_TEXT::MirrorVertical( const wxPoint& center ) +{ + m_Pos.y -= center.y; + m_Pos.y *= -1; + m_Pos.y += center.y; +} + +void LIB_TEXT::Rotate( const wxPoint& center, bool aRotateCCW ) +{ + int rot_angle = aRotateCCW ? -900 : 900; + + RotatePoint( &m_Pos, center, rot_angle ); + m_Orient = m_Orient ? 0 : 900; +} + + +void LIB_TEXT::Plot( PLOTTER* plotter, const wxPoint& offset, bool fill, + const TRANSFORM& aTransform ) +{ + wxASSERT( plotter != NULL ); + + EDA_RECT bBox = GetBoundingBox(); + // convert coordinates from draw Y axis to libedit Y axis + bBox.RevertYAxis(); + wxPoint txtpos = bBox.Centre(); + + /* The text orientation may need to be flipped if the + * transformation matrix causes xy axes to be flipped. */ + int t1 = ( aTransform.x1 != 0 ) ^ ( m_Orient != 0 ); + wxPoint pos = aTransform.TransformCoordinate( txtpos ) + offset; + + // Get color + EDA_COLOR_T color; + + if( plotter->GetColorMode() ) // Used normal color or selected color + color = IsSelected() ? GetItemSelectedColor() : GetDefaultColor(); + else + color = BLACK; + + plotter->Text( pos, color, GetShownText(), + t1 ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT, + m_Size, GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, + GetPenSize(), m_Italic, m_Bold ); +} + + +int LIB_TEXT::GetPenSize() const +{ + int pensize = m_Thickness; + + if( pensize == 0 ) // Use default values for pen size + { + if( m_Bold ) + pensize = GetPenSizeForBold( m_Size.x ); + else + pensize = GetDefaultLineThickness(); + } + + // Clip pen size for small texts: + pensize = Clamp_Text_PenSize( pensize, m_Size, m_Bold ); + return pensize; +} + + +void LIB_TEXT::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ) +{ + EDA_COLOR_T color = GetDefaultColor(); + + if( aColor < 0 ) // Used normal color or selected color + { + if( IsSelected() ) + color = GetItemSelectedColor(); + } + else + { + color = aColor; + } + + GRSetDrawMode( aDC, aDrawMode ); + + /* Calculate the text orientation, according to the component + * orientation/mirror (needed when draw text in schematic) + */ + int orient = m_Orient; + + if( aTransform.y1 ) // Rotate component 90 degrees. + { + if( orient == TEXT_ORIENT_HORIZ ) + orient = TEXT_ORIENT_VERT; + else + orient = TEXT_ORIENT_HORIZ; + } + + /* Calculate the text justification, according to the component + * orientation/mirror this is a bit complicated due to cumulative + * calculations: + * - numerous cases (mirrored or not, rotation) + * - the DrawGraphicText function recalculate also H and H justifications + * according to the text orientation. + * - When a component is mirrored, the text is not mirrored and + * justifications are complicated to calculate + * so the more easily way is to use no justifications ( Centered text ) + * and use GetBoundaryBox to know the text coordinate considered as centered + */ + EDA_RECT bBox = GetBoundingBox(); + // convert coordinates from draw Y axis to libedit Y axis: + bBox.RevertYAxis(); + wxPoint txtpos = bBox.Centre(); + + // Calculate pos according to mirror/rotation. + txtpos = aTransform.TransformCoordinate( txtpos ) + aOffset; + + EDA_RECT* clipbox = aPanel? aPanel->GetClipBox() : NULL; + DrawGraphicText( clipbox, aDC, txtpos, color, GetShownText(), orient, m_Size, + GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, GetPenSize(), + m_Italic, m_Bold ); + + + /* Enable this to draw the bounding box around the text field to validate + * the bounding box calculations. + */ +#if 0 + // bBox already uses libedit Y axis. + bBox = aTransform.TransformCoordinate( bBox ); + bBox.Move( aOffset ); + GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA ); +#endif +} + + +void LIB_TEXT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + LIB_ITEM::GetMsgPanelInfo( aList ); + + msg = StringFromValue( g_UserUnit, m_Thickness, true ); + + aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) ); +} + + +const EDA_RECT LIB_TEXT::GetBoundingBox() const +{ + /* Y coordinates for LIB_ITEMS are bottom to top, so we must invert the Y position when + * calling GetTextBox() that works using top to bottom Y axis orientation. + */ + EDA_RECT rect = GetTextBox( -1, -1, true ); + rect.RevertYAxis(); + + // We are using now a bottom to top Y axis. + wxPoint orig = rect.GetOrigin(); + wxPoint end = rect.GetEnd(); + RotatePoint( &orig, m_Pos, -m_Orient ); + RotatePoint( &end, m_Pos, -m_Orient ); + + rect.SetOrigin( orig ); + rect.SetEnd( end ); + + // We are using now a top to bottom Y axis: + rect.RevertYAxis(); + + return rect; +} + + +void LIB_TEXT::Rotate() +{ + if( InEditMode() ) + { + m_rotate = true; + } + else + { + m_Orient = ( m_Orient == TEXT_ORIENT_VERT ) ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT; + } +} + + +void LIB_TEXT::SetText( const wxString& aText ) +{ + if( aText == m_Text ) + return; + + if( InEditMode() ) + { + m_savedText = aText; + m_updateText = true; + } + else + { + m_Text = aText; + } +} + + +wxString LIB_TEXT::GetSelectMenuText() const +{ + wxString msg; + msg.Printf( _( "Graphic Text %s" ), GetChars( ShortenedShownText() ) ); + return msg; +} + + +void LIB_TEXT::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition ) +{ + wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED ) ) != 0, + wxT( "Invalid edit mode for LIB_TEXT object." ) ); + + if( aEditMode == IS_MOVED ) + { + m_initialPos = m_Pos; + m_initialCursorPos = aPosition; + SetEraseLastDrawItem(); + } + else + { + m_Pos = aPosition; + } + + m_Flags = aEditMode; +} + + +bool LIB_TEXT::ContinueEdit( const wxPoint aPosition ) +{ + wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED ) ) != 0, false, + wxT( "Bad call to ContinueEdit(). Text is not being edited." ) ); + + return false; +} + + +void LIB_TEXT::EndEdit( const wxPoint& aPosition, bool aAbort ) +{ + wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED ) ) != 0, + wxT( "Bad call to EndEdit(). Text is not being edited." ) ); + + m_Flags = 0; + m_rotate = false; + m_updateText = false; + SetEraseLastDrawItem( false ); +} + + +void LIB_TEXT::calcEdit( const wxPoint& aPosition ) +{ + if( m_rotate ) + { + m_Orient = ( m_Orient == TEXT_ORIENT_VERT ) ? TEXT_ORIENT_HORIZ : TEXT_ORIENT_VERT; + m_rotate = false; + } + + if( m_updateText ) + { + std::swap( m_Text, m_savedText ); + m_updateText = false; + } + + if( m_Flags == IS_NEW ) + { + SetEraseLastDrawItem(); + m_Pos = aPosition; + } + else if( m_Flags == IS_MOVED ) + { + Move( m_initialPos + aPosition - m_initialCursorPos ); + } +} diff --git a/eeschema/lib_text.h b/eeschema/lib_text.h new file mode 100644 index 00000000..518678b7 --- /dev/null +++ b/eeschema/lib_text.h @@ -0,0 +1,152 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file lib_text.h + */ + +#ifndef _LIB_TEXT_H_ +#define _LIB_TEXT_H_ + +#include +#include + + +/** + * Class LIB_TEXT + * defines a component library graphical text item. + *

      + * This is only a graphical text item. Field text like the reference designator, + * component value, etc. are not LIB_TEXT items. See the #LIB_FIELD class for the + * field item definition. + *

      + */ +class LIB_TEXT : public LIB_ITEM, public EDA_TEXT +{ + wxString m_savedText; ///< Temporary storage for the string when edition. + bool m_rotate; ///< Flag to indicate a rotation occurred while editing. + bool m_updateText; ///< Flag to indicate text change occurred while editing. + + void drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, GR_DRAWMODE aDrawMode, void* aData, + const TRANSFORM& aTransform ); + + void calcEdit( const wxPoint& aPosition ); + +public: + LIB_TEXT( LIB_PART * aParent ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~LIB_TEXT() { } + + wxString GetClass() const + { + return wxT( "LIB_TEXT" ); + } + + /** + * Sets the text item string to \a aText. + * + * This method does more than just set the set the text string. There are special + * cases when changing the text string alone is not enough. If the text item is + * being moved, the name change must be delayed until the next redraw to prevent + * drawing artifacts. + * + * @param aText - New text value. + */ + void SetText( const wxString& aText ); + + bool Save( OUTPUTFORMATTER& aFormatter ); + + bool Load( LINE_READER& aLineReader, wxString& aErrorMsg ); + + bool HitTest( const wxPoint& aPosition ) const; + + bool HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const; + + bool HitTest( const EDA_RECT& aRect ) const + { + return TextHitTest( aRect ); + } + + + int GetPenSize( ) const; + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + const EDA_RECT GetBoundingBox() const; // virtual + + void Rotate(); + + void BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aStartPoint = wxPoint( 0, 0 ) ); + + bool ContinueEdit( const wxPoint aNextPoint ); + + void EndEdit( const wxPoint& aPosition, bool aAbort = false ); + + void SetOffset( const wxPoint& aOffset ); + + bool Inside( EDA_RECT& aRect ) const; + + void Move( const wxPoint& aPosition ); + + wxPoint GetPosition() const { return m_Pos; } + + void MirrorHorizontal( const wxPoint& aCenter ); + + void MirrorVertical( const wxPoint& aCenter ); + + void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ); + + void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, + const TRANSFORM& aTransform ); + + int GetWidth() const { return m_Thickness; } + + void SetWidth( int aWidth ) { m_Thickness = aWidth; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_text_xpm; } + + EDA_ITEM* Clone() const; + +private: + + /** + * @copydoc LIB_ITEM::compare() + * + * The text specific sort order is as follows: + * - Text string, case insensitive compare. + * - Text horizontal (X) position. + * - Text vertical (Y) position. + * - Text width. + * - Text height. + */ + int compare( const LIB_ITEM& aOther ) const; +}; + + +#endif // _LIB_TEXT_H_ diff --git a/eeschema/libarch.cpp b/eeschema/libarch.cpp new file mode 100644 index 00000000..100b6aa7 --- /dev/null +++ b/eeschema/libarch.cpp @@ -0,0 +1,119 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jp.charras ar wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file libarch.cpp + * @brief Module for generation of component archive files. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +bool SCH_EDIT_FRAME::CreateArchiveLibraryCacheFile( bool aUseCurrentSheetFilename ) +{ + wxFileName fn; + + if( aUseCurrentSheetFilename ) + fn = GetScreen()->GetFileName(); + else + fn = g_RootSheet->GetScreen()->GetFileName(); + + fn.SetName( fn.GetName() + wxT( "-cache" ) ); + fn.SetExt( SchematicLibraryFileExtension ); + + return CreateArchiveLibrary( fn.GetFullPath() ); +} + + +bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName ) +{ + SCH_SCREENS screens; + PART_LIBS* libs = Prj().SchLibs(); + + std::auto_ptr libCache( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) ); + + libCache->SetCache(); + + /* examine all screens (not sheets) used and build the list of components + * found in lib. + * Complex hierarchies are not a problem because we just want + * to know used components in libraries + */ + for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() ) + { + for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + // If not already saved in the new cache, put it: + if( !libCache->FindEntry( component->GetPartName() ) ) + { + if( LIB_PART* part = libs->FindLibPart( component->GetPartName() ) ) + { + // AddPart() does first clone the part before adding. + libCache->AddPart( part ); + } + } + } + } + + try + { + FILE_OUTPUTFORMATTER formatter( aFileName ); + + if( !libCache->Save( formatter ) ) + { + wxString msg = wxString::Format( _( + "An error occurred attempting to save component library '%s'." ), + GetChars( aFileName ) + ); + DisplayError( this, msg ); + return false; + } + } + catch( ... /* IO_ERROR ioe */ ) + { + wxString msg = wxString::Format( _( + "Failed to create component library file '%s'" ), + GetChars( aFileName ) + ); + DisplayError( this, msg ); + return false; + } + + return true; +} diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp new file mode 100644 index 00000000..fe2f1213 --- /dev/null +++ b/eeschema/libedit.cpp @@ -0,0 +1,742 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2013 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file libedit.cpp + * @brief Eeschema component library editor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +void LIB_EDIT_FRAME::DisplayLibInfos() +{ + wxString msg = _( "Part Library Editor: " ); + PART_LIB* lib = GetCurLib(); + + if( lib ) + { + msg += lib->GetFullFileName(); + + if( lib->IsReadOnly() ) + msg += _( " [Read Only]" ); + } + else + { + msg += _( "no library selected" ); + } + + SetTitle( msg ); +} + + +void LIB_EDIT_FRAME::SelectActiveLibrary( PART_LIB* aLibrary ) +{ + if( !aLibrary ) + aLibrary = SelectLibraryFromList(); + + if( aLibrary ) + { + SetCurLib( aLibrary ); + } + + DisplayLibInfos(); +} + + +bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( LIB_ALIAS* aLibEntry, PART_LIB* aLibrary ) +{ + if( GetScreen()->IsModify() + && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) ) + return false; + + SelectActiveLibrary( aLibrary ); + return LoadComponentFromCurrentLib( aLibEntry ); +} + + +bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry ) +{ + if( !LoadOneLibraryPartAux( aLibEntry, GetCurLib() ) ) + return false; + + m_editPinsPerPartOrConvert = GetCurPart()->UnitsLocked() ? true : false; + + GetScreen()->ClearUndoRedoList(); + Zoom_Automatique( false ); + SetShowDeMorgan( GetCurPart()->HasConversion() ); + + return true; +} + + +void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event ) +{ + wxString cmp_name; + LIB_ALIAS* libEntry = NULL; + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + if( GetScreen()->IsModify() + && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) ) + return; + + PART_LIB* lib = GetCurLib(); + + // No current lib, ask user for the library to use. + if( !lib ) + { + SelectActiveLibrary(); + lib = GetCurLib(); + + if( !lib ) + return; + } + + wxArrayString dummyHistoryList; + int dummyLastUnit; + SCHLIB_FILTER filter; + filter.LoadFrom( lib->GetName() ); + cmp_name = SelectComponentFromLibrary( &filter, dummyHistoryList, dummyLastUnit, + true, NULL, NULL ); + + if( cmp_name.IsEmpty() ) + return; + + GetScreen()->ClrModify(); + m_lastDrawItem = m_drawItem = NULL; + + // Delete previous library component, if any + SetCurPart( NULL ); + m_aliasName.Empty(); + + // Load the new library component + libEntry = lib->FindEntry( cmp_name ); + PART_LIB* searchLib = lib; + + if( !libEntry ) + { + // Not found in the active library: search inside the full list + // (can happen when using Viewlib to load a component) + libEntry = Prj().SchLibs()->FindLibraryEntry( cmp_name ); + + if( libEntry ) + { + searchLib = libEntry->GetLib(); + + // The entry to load is not in the active lib + // Ask for a new active lib + wxString msg = _( "The selected component is not in the active library." ); + msg += wxT("\n\n"); + msg += _( "Do you want to change the active library?" ); + + if( IsOK( this, msg ) ) + SelectActiveLibrary( searchLib ); + } + } + + if( !libEntry ) + { + wxString msg = wxString::Format( _( + "Part name '%s' not found in library '%s'" ), + GetChars( cmp_name ), + GetChars( searchLib->GetName() ) + ); + DisplayError( this, msg ); + return; + } + + PART_LIB* old = SetCurLib( searchLib ); + + LoadComponentFromCurrentLib( libEntry ); + + SetCurLib( old ); + + DisplayLibInfos(); +} + + +bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, PART_LIB* aLibrary ) +{ + wxString msg, rootName; + + if( !aEntry || !aLibrary ) + return false; + + if( aEntry->GetName().IsEmpty() ) + { + wxLogWarning( wxT( "Entry in library <%s> has empty name field." ), + GetChars( aLibrary->GetName() ) ); + return false; + } + + wxString cmpName = m_aliasName = aEntry->GetName(); + + LIB_PART* lib_part = aEntry->GetPart(); + + wxASSERT( lib_part ); + + wxLogDebug( wxT( "\"<%s>\" is alias of \"<%s>\"" ), + GetChars( cmpName ), + GetChars( lib_part->GetName() ) ); + + LIB_PART* part = new LIB_PART( *lib_part ); // clone it and own it. + SetCurPart( part ); + m_aliasName = aEntry->GetName(); + + m_unit = 1; + m_convert = 1; + + m_showDeMorgan = false; + + if( part->HasConversion() ) + m_showDeMorgan = true; + + GetScreen()->ClrModify(); + DisplayLibInfos(); + UpdateAliasSelectList(); + UpdatePartSelectList(); + + // Display the document information based on the entry selected just in + // case the entry is an alias. + DisplayCmpDoc(); + + return true; +} + + +void LIB_EDIT_FRAME::RedrawComponent( wxDC* aDC, wxPoint aOffset ) +{ + LIB_PART* part = GetCurPart(); + + if( part ) + { + // display reference like in schematic (a reference U is shown U? or U?A) + // although it is stored without ? and part id. + // So temporary change the reference by a schematic like reference + LIB_FIELD* field = part->GetField( REFERENCE ); + wxString fieldText = field->GetText(); + wxString fieldfullText = field->GetFullText( m_unit ); + + field->EDA_TEXT::SetText( fieldfullText ); // change the field text string only + part->Draw( m_canvas, aDC, aOffset, m_unit, m_convert, GR_DEFAULT_DRAWMODE ); + field->EDA_TEXT::SetText( fieldText ); // restore the field text string + } +} + +void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg ) +{ + if( GetScreen() == NULL ) + return; + + m_canvas->DrawBackGround( DC ); + + RedrawComponent( DC, wxPoint( 0, 0 ) ); + +#ifdef USE_WX_OVERLAY + if( IsShown() ) + { + m_overlay.Reset(); + wxDCOverlay overlaydc( m_overlay, (wxWindowDC*)DC ); + overlaydc.Clear(); + } +#endif + + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + + m_canvas->DrawCrossHair( DC ); + + DisplayLibInfos(); + UpdateStatusBar(); +} + + +void LIB_EDIT_FRAME::OnSaveActiveLibrary( wxCommandEvent& event ) +{ + bool newFile = false; + if( event.GetId() == ID_LIBEDIT_SAVE_CURRENT_LIB_AS ) + newFile = true; + + this->SaveActiveLibrary( newFile ); +} + + +bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) +{ + wxFileName fn; + wxString msg; + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + PART_LIB* lib = GetCurLib(); + + if( !lib ) + { + DisplayError( this, _( "No library specified." ) ); + return false; + } + + if( GetScreen()->IsModify() ) + { + if( IsOK( this, _( "Include last component changes?" ) ) ) + SaveOnePart( lib, false ); + } + + if( newFile ) + { + PROJECT& prj = Prj(); + SEARCH_STACK* search = prj.SchSearchS(); + + // Get a new name for the library + wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); + + if( !default_path ) + default_path = search->LastVisitedPath(); + + wxFileDialog dlg( this, _( "Part Library Name:" ), default_path, + wxEmptyString, SchematicLibraryFileWildcard, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + fn = dlg.GetPath(); + + // The GTK file chooser doesn't return the file extension added to + // file name so add it here. + if( fn.GetExt().IsEmpty() ) + fn.SetExt( SchematicLibraryFileExtension ); + + prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() ); + } + else + { + fn = wxFileName( lib->GetFullFileName() ); + + msg.Printf( _( "Modify library file '%s' ?" ), + GetChars( fn.GetFullPath() ) ); + + if( !IsOK( this, msg ) ) + return false; + } + + // Verify the user has write privileges before attempting to + // save the library file. + if( !IsWritable( fn ) ) + return false; + + ClearMsgPanel(); + + wxFileName libFileName = fn; + wxFileName backupFileName = fn; + + // Rename the old .lib file to .bak. + if( libFileName.FileExists() ) + { + backupFileName.SetExt( wxT( "bak" ) ); + + if( backupFileName.FileExists() ) + wxRemoveFile( backupFileName.GetFullPath() ); + + if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) ) + { + libFileName.MakeAbsolute(); + msg = wxT( "Failed to rename old component library file " ) + + backupFileName.GetFullPath(); + DisplayError( this, msg ); + } + } + + try + { + FILE_OUTPUTFORMATTER libFormatter( libFileName.GetFullPath() ); + + if( !lib->Save( libFormatter ) ) + { + msg.Printf( _( "Error occurred while saving library file '%s'" ), + GetChars( fn.GetFullPath() ) ); + AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED ); + DisplayError( this, msg ); + return false; + } + } + catch( ... /* IO_ERROR ioe */ ) + { + libFileName.MakeAbsolute(); + msg.Printf( _( "Failed to create component library file '%s'" ), + GetChars( libFileName.GetFullPath() ) ); + DisplayError( this, msg ); + return false; + } + + wxFileName docFileName = libFileName; + + docFileName.SetExt( DOC_EXT ); + + // Rename .doc file to .bck. + if( docFileName.FileExists() ) + { + backupFileName.SetExt( wxT( "bck" ) ); + + if( backupFileName.FileExists() ) + wxRemoveFile( backupFileName.GetFullPath() ); + + if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) ) + { + msg = wxT( "Failed to save old library document file " ) + + backupFileName.GetFullPath(); + DisplayError( this, msg ); + } + } + + try + { + FILE_OUTPUTFORMATTER docFormatter( docFileName.GetFullPath() ); + + if( !lib->SaveDocs( docFormatter ) ) + { + msg.Printf( _( "Error occurred while saving library documentation file <%s>" ), + GetChars( docFileName.GetFullPath() ) ); + AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED ); + DisplayError( this, msg ); + return false; + } + } + catch( ... /* IO_ERROR ioe */ ) + { + docFileName.MakeAbsolute(); + msg.Printf( _( "Failed to create component document library file <%s>" ), + GetChars( docFileName.GetFullPath() ) ); + DisplayError( this, msg ); + return false; + } + + msg.Printf( _( "Library file '%s' OK" ), GetChars( fn.GetFullName() ) ); + fn.SetExt( DOC_EXT ); + wxString msg1; + msg1.Printf( _( "Documentation file '%s' OK" ), GetChars( fn.GetFullPath() ) ); + AppendMsgPanel( msg, msg1, BLUE ); + + return true; +} + + +void LIB_EDIT_FRAME::DisplayCmpDoc() +{ + LIB_ALIAS* alias; + PART_LIB* lib = GetCurLib(); + LIB_PART* part = GetCurPart(); + + ClearMsgPanel(); + + if( !lib || !part ) + return; + + wxString msg = part->GetName(); + + AppendMsgPanel( _( "Name" ), msg, BLUE, 8 ); + + if( m_aliasName == part->GetName() ) + msg = _( "None" ); + else + msg = m_aliasName; + + alias = part->GetAlias( m_aliasName ); + + wxCHECK_RET( alias != NULL, wxT( "Alias not found in component." ) ); + + AppendMsgPanel( _( "Alias" ), msg, RED, 8 ); + + static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); + msg = UnitLetter[m_unit]; + + AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 ); + + if( m_convert > 1 ) + msg = _( "Convert" ); + else + msg = _( "Normal" ); + + AppendMsgPanel( _( "Body" ), msg, GREEN, 8 ); + + if( part->IsPower() ) + msg = _( "Power Symbol" ); + else + msg = _( "Part" ); + + AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 ); + AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 ); + AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY ); + AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY ); +} + + +void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event ) +{ + wxString cmp_name; + LIB_ALIAS* libEntry; + wxArrayString nameList; + wxString msg; + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + m_lastDrawItem = NULL; + m_drawItem = NULL; + + PART_LIB* lib = GetCurLib(); + + if( !lib ) + { + SelectActiveLibrary(); + + lib = GetCurLib(); + if( !lib ) + { + DisplayError( this, _( "Please select a component library." ) ); + return; + } + } + + lib->GetEntryNames( nameList ); + + if( nameList.IsEmpty() ) + { + msg.Printf( _( "Part library '%s' is empty." ), GetChars( lib->GetName() ) ); + wxMessageBox( msg, _( "Delete Entry Error" ), wxID_OK | wxICON_EXCLAMATION, this ); + return; + } + + msg.Printf( _( "Select one of %d components to delete\nfrom library '%s'." ), + int( nameList.GetCount() ), + GetChars( lib->GetName() ) ); + + wxSingleChoiceDialog dlg( this, msg, _( "Delete Part" ), nameList ); + + if( dlg.ShowModal() == wxID_CANCEL || dlg.GetStringSelection().IsEmpty() ) + return; + + libEntry = lib->FindEntry( dlg.GetStringSelection() ); + + if( !libEntry ) + { + msg.Printf( _( "Entry '%s' not found in library '%s'." ), + GetChars( dlg.GetStringSelection() ), + GetChars( lib->GetName() ) ); + DisplayError( this, msg ); + return; + } + + msg.Printf( _( "Delete component '%s' from library '%s' ?" ), + GetChars( libEntry->GetName() ), + GetChars( lib->GetName() ) ); + + if( !IsOK( this, msg ) ) + return; + + LIB_PART* part = GetCurPart(); + + if( !part || !part->HasAlias( libEntry->GetName() ) ) + { + lib->RemoveEntry( libEntry ); + return; + } + + // If deleting the current entry or removing one of the aliases for + // the current entry, sync the changes in the current entry as well. + + if( GetScreen()->IsModify() && !IsOK( this, _( + "The component being deleted has been modified." + " All changes will be lost. Discard changes?" ) ) ) + { + return; + } + + LIB_ALIAS* nextEntry = lib->RemoveEntry( libEntry ); + + if( nextEntry != NULL ) + { + if( LoadOneLibraryPartAux( nextEntry, lib ) ) + Zoom_Automatique( false ); + } + else + { + SetCurPart( NULL ); // delete CurPart + m_aliasName.Empty(); + } + + m_canvas->Refresh(); +} + + + +void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event ) +{ + wxString name; + + if( GetCurPart() && GetScreen()->IsModify() && !IsOK( this, _( + "All changes to the current component will be lost!\n\n" + "Clear the current component from the screen?" ) ) ) + { + return; + } + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + m_drawItem = NULL; + + DIALOG_LIB_NEW_COMPONENT dlg( this ); + + dlg.SetMinSize( dlg.GetSize() ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + if( dlg.GetName().IsEmpty() ) + { + wxMessageBox( _( "This new component has no name and cannot be created. Aborted" ) ); + return; + } + + name = dlg.GetName(); + name.Replace( wxT( " " ), wxT( "_" ) ); + + PART_LIB* lib = GetCurLib(); + + // Test if there a component with this name already. + if( lib && lib->FindEntry( name ) ) + { + wxString msg = wxString::Format( _( + "Part '%s' already exists in library '%s'" ), + GetChars( name ), + GetChars( lib->GetName() ) + ); + DisplayError( this, msg ); + return; + } + + LIB_PART* new_part = new LIB_PART( name ); + + SetCurPart( new_part ); + m_aliasName = new_part->GetName(); + + new_part->GetReferenceField().SetText( dlg.GetReference() ); + new_part->SetUnitCount( dlg.GetUnitCount() ); + + // Initialize new_part->m_TextInside member: + // if 0, pin text is outside the body (on the pin) + // if > 0, pin text is inside the body + new_part->SetConversion( dlg.GetAlternateBodyStyle() ); + SetShowDeMorgan( dlg.GetAlternateBodyStyle() ); + + if( dlg.GetPinNameInside() ) + { + new_part->SetPinNameOffset( dlg.GetPinTextPosition() ); + + if( new_part->GetPinNameOffset() == 0 ) + new_part->SetPinNameOffset( 1 ); + } + else + { + new_part->SetPinNameOffset( 0 ); + } + + ( dlg.GetPowerSymbol() ) ? new_part->SetPower() : new_part->SetNormal(); + new_part->SetShowPinNumbers( dlg.GetShowPinNumber() ); + new_part->SetShowPinNames( dlg.GetShowPinName() ); + new_part->LockUnits( dlg.GetLockItems() ); + + if( dlg.GetUnitCount() < 2 ) + new_part->LockUnits( false ); + + m_unit = 1; + m_convert = 1; + + DisplayLibInfos(); + DisplayCmpDoc(); + UpdateAliasSelectList(); + UpdatePartSelectList(); + + m_editPinsPerPartOrConvert = new_part->UnitsLocked() ? true : false; + m_lastDrawItem = NULL; + + GetScreen()->ClearUndoRedoList(); + OnModify(); + + m_canvas->Refresh(); + m_mainToolBar->Refresh(); +} + + +bool LIB_EDIT_FRAME::SaveOnePart( PART_LIB* aLib, bool aPromptUser ) +{ + wxString msg; + LIB_PART* part = GetCurPart(); + + GetScreen()->ClrModify(); + + LIB_PART* old_part = aLib->FindPart( part->GetName() ); + + if( old_part && aPromptUser ) + { + msg.Printf( _( "Part '%s' already exists. Change it?" ), + GetChars( part->GetName() ) ); + + if( !IsOK( this, msg ) ) + return false; + } + + m_drawItem = m_lastDrawItem = NULL; + + if( old_part ) + aLib->ReplacePart( old_part, part ); + else + aLib->AddPart( part ); + + msg.Printf( _( "Part '%s' saved in library '%s'" ), + GetChars( part->GetName() ), + GetChars( aLib->GetName() ) ); + + SetStatusText( msg ); + + return true; +} diff --git a/eeschema/libedit_onleftclick.cpp b/eeschema/libedit_onleftclick.cpp new file mode 100644 index 00000000..5ee53d96 --- /dev/null +++ b/eeschema/libedit_onleftclick.cpp @@ -0,0 +1,213 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2013 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 + */ + +/** + * @file libedit_onleftclick.cpp + * @brief Eeschema library editor event handler for a mouse left button single or double click. + */ + +#include +#include +#include +#include + +#include +#include +#include + + +void LIB_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition ) +{ + LIB_ITEM* item = m_drawItem; + bool item_in_edit = item && item->InEditMode(); + bool no_item_edited = !item_in_edit; + + LIB_PART* part = GetCurPart(); + + if( !part ) // No component loaded ! + return; + + if( ( GetToolId() == ID_NO_TOOL_SELECTED ) && no_item_edited ) + { + item = LocateItemUsingCursor( aPosition ); + + if( item ) + { + MSG_PANEL_ITEMS items; + item->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + } + else + { + DisplayCmpDoc(); + + if( m_canvas->GetAbortRequest() ) + m_canvas->SetAbortRequest( false ); + } + } + + switch( GetToolId() ) + { + case ID_NO_TOOL_SELECTED: + // If an item is currently in edit, finish edit + if( item_in_edit ) + { + switch( item->Type() ) + { + case LIB_PIN_T: + PlacePin(); + break; + + default: + EndDrawGraphicItem( DC ); + break; + } + } + break; + + case ID_LIBEDIT_PIN_BUTT: + if( no_item_edited ) + CreatePin( DC ); + else + PlacePin(); + break; + + case ID_LIBEDIT_BODY_LINE_BUTT: + case ID_LIBEDIT_BODY_ARC_BUTT: + case ID_LIBEDIT_BODY_CIRCLE_BUTT: + case ID_LIBEDIT_BODY_RECT_BUTT: + case ID_LIBEDIT_BODY_TEXT_BUTT: + if( no_item_edited ) + m_drawItem = CreateGraphicItem( part, DC ); + else if( m_drawItem ) + { + if( m_drawItem->IsNew() ) + GraphicItemBeginDraw( DC ); + else + EndDrawGraphicItem( DC ); + } + break; + + case ID_LIBEDIT_DELETE_ITEM_BUTT: + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem ) + deleteItem( DC ); + else + DisplayCmpDoc(); + + break; + + case ID_LIBEDIT_ANCHOR_ITEM_BUTT: + SaveCopyInUndoList( part ); + PlaceAnchor(); + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Unhandled command ID %d" ), GetToolId() ) ); + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; + } +} + + +/* + * Called on a double click: + * If an editable item (field, pin, graphic): + * Call the suitable dialog editor. + */ +void LIB_EDIT_FRAME::OnLeftDClick( wxDC* DC, const wxPoint& aPosition ) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + if( !m_drawItem || !m_drawItem->InEditMode() ) + { // We can locate an item + m_drawItem = LocateItemUsingCursor( aPosition ); + + if( m_drawItem == NULL ) + { + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + + cmd.SetId( ID_LIBEDIT_GET_FRAME_EDIT_PART ); + GetEventHandler()->ProcessEvent( cmd ); + } + } + + if( m_drawItem ) + SetMsgPanel( m_drawItem ); + else + return; + + m_canvas->SetIgnoreMouseEvents( true ); + bool not_edited = !m_drawItem->InEditMode(); + + switch( m_drawItem->Type() ) + { + case LIB_PIN_T: + if( not_edited ) + { + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + + cmd.SetId( ID_LIBEDIT_EDIT_PIN ); + GetEventHandler()->ProcessEvent( cmd ); + } + break; + + case LIB_ARC_T: + case LIB_CIRCLE_T: + case LIB_RECTANGLE_T: + if( not_edited ) + EditGraphicSymbol( DC, m_drawItem ); + break; + + case LIB_POLYLINE_T: + if( not_edited ) + EditGraphicSymbol( DC, m_drawItem ); + else if( m_drawItem->IsNew() ) + EndDrawGraphicItem( DC ); + break; + + case LIB_TEXT_T: + if( not_edited ) + EditSymbolText( DC, m_drawItem ); + break; + + case LIB_FIELD_T: + if( not_edited ) + EditField( (LIB_FIELD*) m_drawItem ); + break; + + default: + wxFAIL_MSG( wxT( "Unhandled item <" ) + m_drawItem->GetClass() + wxT( ">" ) ); + break; + } + + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); +} diff --git a/eeschema/libedit_onrightclick.cpp b/eeschema/libedit_onrightclick.cpp new file mode 100644 index 00000000..24067ed2 --- /dev/null +++ b/eeschema/libedit_onrightclick.cpp @@ -0,0 +1,348 @@ +/** + * @file libedit_onrightclick.cpp + * @brief Library editor: create the pop menus when clicking on mouse right button + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2014 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* functions to add commands and submenus depending on the item */ +static void AddMenusForBlock( wxMenu* PopMenu, LIB_EDIT_FRAME* frame ); +static void AddMenusForPin( wxMenu* PopMenu, LIB_PIN* Pin, LIB_EDIT_FRAME* frame ); + + +bool LIB_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu ) +{ + LIB_ITEM* item = GetDrawItem(); + bool blockActive = GetScreen()->IsBlockActive(); + + if( blockActive ) + { + AddMenusForBlock( PopMenu, this ); + PopMenu->AppendSeparator(); + return true; + } + + LIB_PART* part = GetCurPart(); + + if( !part ) + return true; + + // If Command in progress, put menu "cancel" + if( item && item->InEditMode() ) + { + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_CANCEL_EDITING, _( "Cancel" ), + KiBitmap( cancel_xpm ) ); + PopMenu->AppendSeparator(); + } + else + { + item = LocateItemUsingCursor( aPosition ); + + // If the clarify item selection context menu is aborted, don't show the context menu. + if( item == NULL && m_canvas->GetAbortRequest() ) + { + m_canvas->SetAbortRequest( false ); + return false; + } + + if( GetToolId() != ID_NO_TOOL_SELECTED ) + { + // If a tool is active, put menu "end tool" + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_CANCEL_EDITING, _( "End Tool" ), + KiBitmap( cursor_xpm ) ); + PopMenu->AppendSeparator(); + } + } + + if( item ) + { + MSG_PANEL_ITEMS items; + item->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + } + else + { + return true; + } + + m_drawItem = item; + bool not_edited = !item->InEditMode(); + wxString msg; + + switch( item->Type() ) + { + case LIB_PIN_T: + AddMenusForPin( PopMenu, (LIB_PIN*) item, this ); + break; + + case LIB_ARC_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Arc" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_arc_xpm ) ); + msg = AddHotkeyName( _( "Drag Arc Size" ), g_Libedit_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MODIFY_ITEM, msg, KiBitmap( move_arc_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Arc Options" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, msg, KiBitmap( options_arc_xpm ) ); + + if( not_edited ) + { + msg = AddHotkeyName( _( "Delete Arc" ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, KiBitmap( delete_arc_xpm ) ); + } + break; + + case LIB_CIRCLE_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Circle" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_circle_xpm ) ); + msg = AddHotkeyName( _( "Drag Circle Outline" ), g_Libedit_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MODIFY_ITEM, msg, + KiBitmap( move_rectangle_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Circle Options" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, msg, + KiBitmap( options_circle_xpm ) ); + + if( not_edited ) + { + msg = AddHotkeyName( _( "Delete Circle" ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, + KiBitmap( delete_circle_xpm ) ); + } + break; + + case LIB_RECTANGLE_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Rectangle" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_rectangle_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Rectangle Options" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, msg, + KiBitmap( options_rectangle_xpm ) ); + + if( not_edited ) + { + msg = AddHotkeyName( _( "Drag Rectangle Edge" ), g_Libedit_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MODIFY_ITEM, msg, + KiBitmap( move_rectangle_xpm ) ); + msg = AddHotkeyName( _( "Delete Rectangle" ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, + KiBitmap( delete_rectangle_xpm ) ); + } + + break; + + case LIB_TEXT_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Text" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_text_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Text" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + + msg = AddHotkeyName( _( "Rotate Text" ), g_Libedit_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_LIBEDIT_ROTATE_ITEM, msg, KiBitmap( edit_text_xpm ) ); + + if( not_edited ) + { + msg = AddHotkeyName( _( "Delete Text" ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, KiBitmap( delete_text_xpm ) ); + } + break; + + case LIB_POLYLINE_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Line" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_line_xpm ) ); + msg = AddHotkeyName( _( "Drag Edge Point" ), g_Libedit_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MODIFY_ITEM, msg, KiBitmap( move_line_xpm ) ); + } + + if( item->IsNew() ) + { + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_END_CREATE_ITEM, _( "Line End" ), + KiBitmap( checked_ok_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Line Options" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_BODY_EDIT_ITEM, msg, + KiBitmap( options_segment_xpm ) ); + + if( not_edited ) + { + msg = AddHotkeyName( _( "Delete Line " ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, + KiBitmap( delete_segment_xpm ) ); + } + + if( item->IsNew() ) + { + if( ( (LIB_POLYLINE*) item )->GetCornerCount() > 2 ) + { + msg = AddHotkeyName( _( "Delete Segment" ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_CURRENT_POLY_SEGMENT, + msg, KiBitmap( delete_segment_xpm ) ); + } + } + + break; + + case LIB_FIELD_T: + if( not_edited ) + { + msg = AddHotkeyName( _( "Move Field" ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, + KiBitmap( move_field_xpm ) ); + } + + msg = AddHotkeyName( _( "Field Rotate" ), g_Libedit_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_LIBEDIT_ROTATE_ITEM, msg, KiBitmap( rotate_field_xpm ) ); + msg = AddHotkeyName( _( "Field Edit" ), g_Libedit_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_FIELD_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + break; + + + default: + wxFAIL_MSG( wxString::Format( wxT( "Unknown library item type %d" ), + item->Type() ) ); + m_drawItem = NULL; + break; + } + + PopMenu->AppendSeparator(); + return true; +} + +// Add menu items for pin edition +void AddMenusForPin( wxMenu* PopMenu, LIB_PIN* Pin, LIB_EDIT_FRAME* frame ) +{ + bool selected = Pin->IsSelected(); + bool not_in_move = !Pin->IsMoving(); + wxString msg; + + if( not_in_move ) + { + msg = AddHotkeyName( _( "Move Pin " ), g_Libedit_Hokeys_Descr, + HK_LIBEDIT_MOVE_GRAPHIC_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST, msg, KiBitmap( move_xpm ) ); + } + + msg = AddHotkeyName( _( "Edit Pin " ), g_Libedit_Hokeys_Descr, HK_EDIT); + AddMenuItem( PopMenu, ID_LIBEDIT_EDIT_PIN, msg, KiBitmap( edit_xpm ) ); + + msg = AddHotkeyName( _( "Rotate Pin " ), g_Libedit_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_LIBEDIT_ROTATE_ITEM, msg, KiBitmap( rotate_pin_xpm ) ); + + if( not_in_move ) + { + msg = AddHotkeyName( _( "Delete Pin " ), g_Libedit_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_DELETE_ITEM, msg, KiBitmap( delete_pin_xpm ) ); + } + + wxMenu* global_pin_change = new wxMenu; + AddMenuItem( PopMenu, global_pin_change, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_ITEM, + _( "Global" ), KiBitmap( pin_to_xpm ) ); + AddMenuItem( global_pin_change, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM, + selected ? _( "Pin Size to selected pins" ) : + _( "Pin Size to Others" ), KiBitmap( pin_size_to_xpm ) ); + AddMenuItem( global_pin_change, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM, + selected ? _( "Pin Name Size to selected pin" ) : + _( "Pin Name Size to Others" ), KiBitmap( pin_name_to_xpm ) ); + AddMenuItem( global_pin_change, + ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM, + selected ? _( "Pin Num Size to selected pin" ) : + _( "Pin Num Size to Others" ), KiBitmap( pin_number_to_xpm ) ); +} + + +/* Add menu commands for block */ + +void AddMenusForBlock( wxMenu* PopMenu, LIB_EDIT_FRAME* frame ) +{ + AddMenuItem( PopMenu, ID_POPUP_LIBEDIT_CANCEL_EDITING, _( "Cancel Block" ), + KiBitmap( cancel_xpm ) ); + + if( frame->GetScreen()->m_BlockLocate.GetCommand() == BLOCK_MOVE ) + AddMenuItem( PopMenu, ID_POPUP_ZOOM_BLOCK, + _( "Zoom Block (drag middle mouse)" ), + KiBitmap( zoom_area_xpm ) ); + + PopMenu->AppendSeparator(); + + AddMenuItem( PopMenu, ID_POPUP_PLACE_BLOCK, _( "Place Block" ), KiBitmap( checked_ok_xpm ) ); + + if( frame->GetScreen()->m_BlockLocate.GetCommand() == BLOCK_MOVE ) + { + AddMenuItem( PopMenu, ID_POPUP_SELECT_ITEMS_BLOCK, _( "Select Items" ), + KiBitmap( green_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_COPY_BLOCK, _( "Copy Block" ), KiBitmap( copyblock_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_MIRROR_Y_BLOCK, _( "Mirror Block ||" ), + KiBitmap( mirror_h_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_MIRROR_X_BLOCK, _( "Mirror Block --" ), + KiBitmap( mirror_v_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_ROTATE_BLOCK, _( "Rotate Block ccw" ), + KiBitmap( rotate_ccw_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_DELETE_BLOCK, _( "Delete Block" ), KiBitmap( delete_xpm ) ); + } +} diff --git a/eeschema/libedit_plot_component.cpp b/eeschema/libedit_plot_component.cpp new file mode 100644 index 00000000..ccdca67a --- /dev/null +++ b/eeschema/libedit_plot_component.cpp @@ -0,0 +1,214 @@ +/** + * @file libedit_plot_component.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2012 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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +void LIB_EDIT_FRAME::OnPlotCurrentComponent( wxCommandEvent& event ) +{ + wxString fullFileName; + wxString file_ext; + wxString mask; + + LIB_PART* part = GetCurPart(); + + if( !part ) + { + wxMessageBox( _( "No component" ) ); + return; + } + + switch( event.GetId() ) + { + case ID_LIBEDIT_GEN_PNG_FILE: + { + bool fmt_is_jpeg = false; // could be selectable later. so keep this option. + + file_ext = fmt_is_jpeg ? wxT( "jpg" ) : wxT( "png" ); + mask = wxT( "*." ) + file_ext; + wxFileName fn( part->GetName() ); + fn.SetExt( file_ext ); + + wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); + + fullFileName = EDA_FILE_SELECTOR( _( "Filename:" ), pro_dir, + fn.GetFullName(), file_ext, mask, this, + wxFD_SAVE, true ); + + if( fullFileName.IsEmpty() ) + return; + + // calling wxYield is mandatory under Linux, after closing the file selector dialog + // to refresh the screen before creating the PNG or JPEG image from screen + wxYield(); + CreatePNGorJPEGFile( fullFileName, fmt_is_jpeg ); + } + break; + + case ID_LIBEDIT_GEN_SVG_FILE: + { + file_ext = wxT( "svg" ); + mask = wxT( "*." ) + file_ext; + wxFileName fn( part->GetName() ); + fn.SetExt( file_ext ); + + wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); + + fullFileName = EDA_FILE_SELECTOR( _( "Filename:" ), pro_dir, + fn.GetFullName(), file_ext, mask, this, + wxFD_SAVE, true ); + + if( fullFileName.IsEmpty() ) + return; + + PAGE_INFO pageSave = GetScreen()->GetPageSettings(); + PAGE_INFO pageTemp = pageSave; + + wxSize componentSize = part->GetBoundingBox( m_unit, m_convert ).GetSize(); + + // Add a small margin to the plot bounding box + pageTemp.SetWidthMils( int( componentSize.x * 1.2 ) ); + pageTemp.SetHeightMils( int( componentSize.y * 1.2 ) ); + + GetScreen()->SetPageSettings( pageTemp ); + SVG_PlotComponent( fullFileName ); + GetScreen()->SetPageSettings( pageSave ); + } + break; + } +} + + +void LIB_EDIT_FRAME::CreatePNGorJPEGFile( const wxString& aFileName, bool aFmt_jpeg ) +{ + wxSize image_size = m_canvas->GetClientSize(); + + wxClientDC dc( m_canvas ); + wxBitmap bitmap( image_size.x, image_size.y ); + wxMemoryDC memdc; + + memdc.SelectObject( bitmap ); + memdc.Blit( 0, 0, image_size.x, image_size.y, &dc, 0, 0 ); + memdc.SelectObject( wxNullBitmap ); + + wxImage image = bitmap.ConvertToImage(); + + if( !image.SaveFile( aFileName, aFmt_jpeg ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG ) ) + { + wxString msg; + msg.Printf( _( "Can't save file <%s>" ), GetChars( aFileName ) ); + wxMessageBox( msg ); + } + + image.Destroy(); +} + + +void LIB_EDIT_FRAME::SVG_PlotComponent( const wxString& aFullFileName ) +{ + const bool plotBW = false; + const PAGE_INFO& pageInfo = GetScreen()->GetPageSettings(); + + SVG_PLOTTER* plotter = new SVG_PLOTTER(); + plotter->SetPageSettings( pageInfo ); + plotter->SetDefaultLineWidth( GetDefaultLineThickness() ); + plotter->SetColorMode( plotBW ); + + wxPoint plot_offset; + const double scale = 1.0; + plotter->SetViewport( plot_offset, IU_PER_DECIMILS, scale, false ); + + // Init : + plotter->SetCreator( wxT( "Eeschema-SVG" ) ); + + if( ! plotter->OpenFile( aFullFileName ) ) + { + delete plotter; + return; + } + + LOCALE_IO toggle; + + plotter->StartPlot(); + + LIB_PART* part = GetCurPart(); + + if( part ) + { + TRANSFORM temp; // Uses default transform + wxPoint plotPos; + + plotPos.x = pageInfo.GetWidthIU() /2; + plotPos.y = pageInfo.GetHeightIU()/2; + + part->Plot( plotter, GetUnit(), GetConvert(), plotPos, temp ); + + // Plot lib fields, not plotted by m_component->Plot(): + part->PlotLibFields( plotter, GetUnit(), GetConvert(), plotPos, temp ); + } + + plotter->EndPlot(); + delete plotter; +} + +void LIB_EDIT_FRAME::PrintPage( wxDC* aDC, LSET aPrintMask, bool aPrintMirrorMode, void* aData) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + wxSize pagesize = GetScreen()->GetPageSettings().GetSizeIU(); + + /* Plot item centered to the page + * In libedit, the component is centered at 0,0 coordinates. + * So we must plot it with an offset = pagesize/2. + */ + wxPoint plot_offset; + plot_offset.x = pagesize.x/2; + plot_offset.y = pagesize.y/2; + + part->Draw( m_canvas, aDC, plot_offset, m_unit, m_convert, GR_DEFAULT_DRAWMODE ); +} + + diff --git a/eeschema/libedit_undo_redo.cpp b/eeschema/libedit_undo_redo.cpp new file mode 100644 index 00000000..a2935008 --- /dev/null +++ b/eeschema/libedit_undo_redo.cpp @@ -0,0 +1,137 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 +#include + +//#include +//#include +#include +#include + + +void LIB_EDIT_FRAME::SaveCopyInUndoList( EDA_ITEM* ItemToCopy ) +{ + LIB_PART* CopyItem; + PICKED_ITEMS_LIST* lastcmd; + + CopyItem = new LIB_PART( * (LIB_PART*) ItemToCopy ); + + // Clear current flags (which can be temporary set by a current edit command). + CopyItem->ClearStatus(); + + lastcmd = new PICKED_ITEMS_LIST(); + ITEM_PICKER wrapper( CopyItem, UR_LIBEDIT ); + lastcmd->PushItem(wrapper); + GetScreen()->PushCommandToUndoList( lastcmd ); + + // Clear redo list, because after new save there is no redo to do. + GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); +} + + +void LIB_EDIT_FRAME::GetComponentFromRedoList( wxCommandEvent& event ) +{ + if( GetScreen()->GetRedoCommandCount() <= 0 ) + return; + + PICKED_ITEMS_LIST* lastcmd = new PICKED_ITEMS_LIST(); + + LIB_PART* part = GetCurPart(); + + ITEM_PICKER wrapper( part, UR_LIBEDIT ); + + lastcmd->PushItem( wrapper ); + GetScreen()->PushCommandToUndoList( lastcmd ); + + lastcmd = GetScreen()->PopCommandFromRedoList(); + + wrapper = lastcmd->PopItem(); + + part = (LIB_PART*) wrapper.GetItem(); + + // Do not delete the previous part by calling SetCurPart( part ) + // which calls delete . + // is now put in undo list and is owned by this list + // Just set the current part to the part which come from the redo list + m_my_part = part; + + if( !part ) + return; + + if( !m_aliasName.IsEmpty() && !part->HasAlias( m_aliasName ) ) + m_aliasName = part->GetName(); + + m_drawItem = NULL; + UpdateAliasSelectList(); + UpdatePartSelectList(); + SetShowDeMorgan( part->HasConversion() ); + DisplayLibInfos(); + DisplayCmpDoc(); + OnModify(); + m_canvas->Refresh(); +} + + +void LIB_EDIT_FRAME::GetComponentFromUndoList( wxCommandEvent& event ) +{ + if( GetScreen()->GetUndoCommandCount() <= 0 ) + return; + + PICKED_ITEMS_LIST* lastcmd = new PICKED_ITEMS_LIST(); + + LIB_PART* part = GetCurPart(); + + ITEM_PICKER wrapper( part, UR_LIBEDIT ); + + lastcmd->PushItem( wrapper ); + GetScreen()->PushCommandToRedoList( lastcmd ); + + lastcmd = GetScreen()->PopCommandFromUndoList(); + + wrapper = lastcmd->PopItem(); + + part = (LIB_PART* ) wrapper.GetItem(); + + // Do not delete the previous part by calling SetCurPart( part ), + // which calls delete . + // is now put in redo list and is owned by this list. + // Just set the current part to the part which come from the undo list + m_my_part = part; + + if( !part ) + return; + + if( !m_aliasName.IsEmpty() && !part->HasAlias( m_aliasName ) ) + m_aliasName = part->GetName(); + + m_drawItem = NULL; + UpdateAliasSelectList(); + UpdatePartSelectList(); + SetShowDeMorgan( part->HasConversion() ); + DisplayLibInfos(); + DisplayCmpDoc(); + OnModify(); + m_canvas->Refresh(); +} diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp new file mode 100644 index 00000000..bd489a0a --- /dev/null +++ b/eeschema/libeditframe.cpp @@ -0,0 +1,1375 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2013 Wayne Stambaugh + * Copyright (C) 2004-2013 KiCad Developers, see change_log.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 + */ + +/** + * @file libeditframe.cpp + * @brief LIB_EDIT_FRAME class is the component library editor frame. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + + +/* This method guarantees unique IDs for the library this run of Eeschema + * which prevents ID conflicts and eliminates the need to recompile every + * source file in the project when adding IDs to include/id.h. */ +int ExportPartId = ::wxNewId(); +int ImportPartId = ::wxNewId(); +int CreateNewLibAndSavePartId = ::wxNewId(); + + +wxString LIB_EDIT_FRAME:: m_aliasName; +int LIB_EDIT_FRAME:: m_unit = 1; +int LIB_EDIT_FRAME:: m_convert = 1; +LIB_ITEM* LIB_EDIT_FRAME::m_lastDrawItem = NULL; +LIB_ITEM* LIB_EDIT_FRAME::m_drawItem = NULL; +bool LIB_EDIT_FRAME:: m_showDeMorgan = false; +wxSize LIB_EDIT_FRAME:: m_clientSize = wxSize( -1, -1 ); +int LIB_EDIT_FRAME:: m_textSize = -1; +int LIB_EDIT_FRAME:: m_textOrientation = TEXT_ORIENT_HORIZ; +int LIB_EDIT_FRAME:: m_drawLineWidth = 0; + +// these values are overridden when reading the config +int LIB_EDIT_FRAME:: m_textPinNumDefaultSize = DEFAULTPINNUMSIZE; +int LIB_EDIT_FRAME:: m_textPinNameDefaultSize = DEFAULTPINNAMESIZE; +int LIB_EDIT_FRAME:: m_defaultPinLength = DEFAULTPINLENGTH; + +FILL_T LIB_EDIT_FRAME:: m_drawFillStyle = NO_FILL; + + +BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) + EVT_CLOSE( LIB_EDIT_FRAME::OnCloseWindow ) + EVT_SIZE( LIB_EDIT_FRAME::OnSize ) + EVT_ACTIVATE( LIB_EDIT_FRAME::OnActivate ) + + // Main horizontal toolbar. + EVT_TOOL( ID_LIBEDIT_SAVE_CURRENT_LIB, LIB_EDIT_FRAME::OnSaveActiveLibrary ) + EVT_TOOL( ID_LIBEDIT_SELECT_CURRENT_LIB, LIB_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( ID_LIBEDIT_DELETE_PART, LIB_EDIT_FRAME::DeleteOnePart ) + EVT_TOOL( ID_TO_LIBVIEW, LIB_EDIT_FRAME::OnOpenLibraryViewer ) + EVT_TOOL( ID_LIBEDIT_NEW_PART, LIB_EDIT_FRAME::CreateNewLibraryPart ) + EVT_TOOL( ID_LIBEDIT_NEW_PART_FROM_EXISTING, LIB_EDIT_FRAME::OnCreateNewPartFromExisting ) + + EVT_TOOL( ID_LIBEDIT_SELECT_PART, LIB_EDIT_FRAME::LoadOneLibraryPart ) + EVT_TOOL( ID_LIBEDIT_SAVE_CURRENT_PART, LIB_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( wxID_UNDO, LIB_EDIT_FRAME::GetComponentFromUndoList ) + EVT_TOOL( wxID_REDO, LIB_EDIT_FRAME::GetComponentFromRedoList ) + EVT_TOOL( ID_LIBEDIT_GET_FRAME_EDIT_PART, LIB_EDIT_FRAME::OnEditComponentProperties ) + EVT_TOOL( ID_LIBEDIT_GET_FRAME_EDIT_FIELDS, LIB_EDIT_FRAME::InstallFieldsEditorDialog ) + EVT_TOOL( ID_LIBEDIT_CHECK_PART, LIB_EDIT_FRAME::OnCheckComponent ) + EVT_TOOL( ID_DE_MORGAN_NORMAL_BUTT, LIB_EDIT_FRAME::OnSelectBodyStyle ) + EVT_TOOL( ID_DE_MORGAN_CONVERT_BUTT, LIB_EDIT_FRAME::OnSelectBodyStyle ) + EVT_TOOL( ID_LIBEDIT_VIEW_DOC, LIB_EDIT_FRAME::OnViewEntryDoc ) + EVT_TOOL( ID_LIBEDIT_EDIT_PIN_BY_PIN, LIB_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( ID_LIBEDIT_EDIT_PIN_BY_TABLE, LIB_EDIT_FRAME::OnOpenPinTable ) + EVT_TOOL( ExportPartId, LIB_EDIT_FRAME::OnExportPart ) + EVT_TOOL( CreateNewLibAndSavePartId, LIB_EDIT_FRAME::OnExportPart ) + EVT_TOOL( ImportPartId, LIB_EDIT_FRAME::OnImportPart ) + + EVT_COMBOBOX( ID_LIBEDIT_SELECT_PART_NUMBER, LIB_EDIT_FRAME::OnSelectPart ) + EVT_COMBOBOX( ID_LIBEDIT_SELECT_ALIAS, LIB_EDIT_FRAME::OnSelectAlias ) + + // Right vertical toolbar. + EVT_TOOL( ID_NO_TOOL_SELECTED, LIB_EDIT_FRAME::OnSelectTool ) + EVT_TOOL_RANGE( ID_LIBEDIT_PIN_BUTT, ID_LIBEDIT_DELETE_ITEM_BUTT, + LIB_EDIT_FRAME::OnSelectTool ) + + // menubar commands + EVT_MENU( wxID_EXIT, LIB_EDIT_FRAME::CloseWindow ) + EVT_MENU( ID_LIBEDIT_SAVE_CURRENT_LIB_AS, LIB_EDIT_FRAME::OnSaveActiveLibrary ) + EVT_MENU( ID_LIBEDIT_GEN_PNG_FILE, LIB_EDIT_FRAME::OnPlotCurrentComponent ) + EVT_MENU( ID_LIBEDIT_GEN_SVG_FILE, LIB_EDIT_FRAME::OnPlotCurrentComponent ) + EVT_MENU( wxID_HELP, EDA_DRAW_FRAME::GetKicadHelp ) + EVT_MENU( wxID_INDEX, EDA_DRAW_FRAME::GetKicadHelp ) + EVT_MENU( wxID_ABOUT, EDA_BASE_FRAME::GetKicadAbout ) + + EVT_MENU( ID_COLORS_SETUP, LIB_EDIT_FRAME::OnColorConfig ) + EVT_MENU( wxID_PREFERENCES, LIB_EDIT_FRAME::OnPreferencesOptions ) + EVT_MENU( ID_CONFIG_REQ, LIB_EDIT_FRAME::InstallConfigFrame ) + EVT_MENU( ID_COLORS_SETUP, LIB_EDIT_FRAME::Process_Config ) + + // Multiple item selection context menu commands. + EVT_MENU_RANGE( ID_SELECT_ITEM_START, ID_SELECT_ITEM_END, LIB_EDIT_FRAME::OnSelectItem ) + + EVT_MENU_RANGE( ID_PREFERENCES_HOTKEY_START, ID_PREFERENCES_HOTKEY_END, + LIB_EDIT_FRAME::Process_Config ) + + // Context menu events and commands. + EVT_MENU( ID_LIBEDIT_EDIT_PIN, LIB_EDIT_FRAME::OnEditPin ) + EVT_MENU( ID_LIBEDIT_ROTATE_ITEM, LIB_EDIT_FRAME::OnRotateItem ) + + EVT_MENU_RANGE( ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_ITEM, + ID_POPUP_LIBEDIT_DELETE_CURRENT_POLY_SEGMENT, + LIB_EDIT_FRAME::Process_Special_Functions ) + + EVT_MENU_RANGE( ID_POPUP_GENERAL_START_RANGE, ID_POPUP_GENERAL_END_RANGE, + LIB_EDIT_FRAME::Process_Special_Functions ) + + // Update user interface elements. + EVT_UPDATE_UI( ExportPartId, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( CreateNewLibAndSavePartId, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_SAVE_CURRENT_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_GET_FRAME_EDIT_FIELDS, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_CHECK_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_GET_FRAME_EDIT_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_NEW_PART_FROM_EXISTING, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( wxID_UNDO, LIB_EDIT_FRAME::OnUpdateUndo ) + EVT_UPDATE_UI( wxID_REDO, LIB_EDIT_FRAME::OnUpdateRedo ) + EVT_UPDATE_UI( ID_LIBEDIT_SAVE_CURRENT_LIB, LIB_EDIT_FRAME::OnUpdateSaveCurrentLib ) + EVT_UPDATE_UI( ID_LIBEDIT_VIEW_DOC, LIB_EDIT_FRAME::OnUpdateViewDoc ) + EVT_UPDATE_UI( ID_LIBEDIT_EDIT_PIN_BY_PIN, LIB_EDIT_FRAME::OnUpdatePinByPin ) + EVT_UPDATE_UI( ID_LIBEDIT_EDIT_PIN_BY_TABLE, LIB_EDIT_FRAME::OnUpdatePinTable ) + EVT_UPDATE_UI( ID_LIBEDIT_SELECT_PART_NUMBER, LIB_EDIT_FRAME::OnUpdatePartNumber ) + EVT_UPDATE_UI( ID_LIBEDIT_SELECT_ALIAS, LIB_EDIT_FRAME::OnUpdateSelectAlias ) + EVT_UPDATE_UI( ID_DE_MORGAN_NORMAL_BUTT, LIB_EDIT_FRAME::OnUpdateDeMorganNormal ) + EVT_UPDATE_UI( ID_DE_MORGAN_CONVERT_BUTT, LIB_EDIT_FRAME::OnUpdateDeMorganConvert ) + EVT_UPDATE_UI( ID_NO_TOOL_SELECTED, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI_RANGE( ID_LIBEDIT_PIN_BUTT, ID_LIBEDIT_DELETE_ITEM_BUTT, + LIB_EDIT_FRAME::OnUpdateEditingPart ) +END_EVENT_TABLE() + +#define LIB_EDIT_FRAME_NAME wxT( "LibeditFrame" ) + +LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH_LIB_EDITOR, _( "Library Editor" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, LIB_EDIT_FRAME_NAME ) +{ + wxASSERT( aParent ); + + m_showAxis = true; // true to draw axis + SetShowDeMorgan( false ); + m_drawSpecificConvert = true; + m_drawSpecificUnit = false; + m_hotkeysDescrList = g_Libedit_Hokeys_Descr; + m_editPinsPerPartOrConvert = false; + m_repeatPinStep = DEFAULT_REPEAT_OFFSET_PIN; + + m_my_part = NULL; + m_tempCopyComponent = NULL; + + // Delayed initialization + if( m_textSize == -1 ) + m_textSize = GetDefaultTextSize(); + + // Initialize grid id to the default value 50 mils: + m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000; + + wxIcon icon; + icon.CopyFromBitmap( KiBitmap( libedit_icon_xpm ) ); + SetIcon( icon ); + + LoadSettings( config() ); + + SetScreen( new SCH_SCREEN( aKiway ) ); + GetScreen()->m_Center = true; + GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax ); + + SetCrossHairPosition( wxPoint( 0, 0 ) ); + + // Ensure m_LastGridSizeId is an offset inside the allowed schematic range + if( m_LastGridSizeId < ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000 ) + m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000; + + if( m_LastGridSizeId > ID_POPUP_GRID_LEVEL_1 - ID_POPUP_GRID_LEVEL_1000 ) + m_LastGridSizeId = ID_POPUP_GRID_LEVEL_1 - ID_POPUP_GRID_LEVEL_1000; + + SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); + + GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); + + if( m_canvas ) + m_canvas->SetEnableBlockCommands( true ); + + ReCreateMenuBar(); + ReCreateHToolbar(); + ReCreateVToolbar(); + + // Ensure the current alias name is valid if a part is loaded + // Sometimes it is not valid. This is the case + // when a part value (the part lib name), or the alias list was modified + // during a previous session and the modifications not saved in lib. + // Reopen libedit in a new session gives a non valid m_aliasName + // because the curr part is reloaded from the library (and this is the unmodified part) + // and the old alias name (from the previous edition) can be invalid + LIB_PART* part = GetCurPart(); + + if( part == NULL ) + m_aliasName.Empty(); + else if( m_aliasName != part->GetName() ) + { + LIB_ALIAS* alias = part->GetAlias( m_aliasName ); + + if( !alias ) + m_aliasName = part->GetName(); + } + + + CreateOptionToolbar(); + DisplayLibInfos(); + DisplayCmpDoc(); + UpdateAliasSelectList(); + UpdatePartSelectList(); + + m_auimgr.SetManagedWindow( this ); + + EDA_PANEINFO horiz; + horiz.HorizontalToolbarPane(); + + EDA_PANEINFO vert; + vert.VerticalToolbarPane(); + + EDA_PANEINFO mesg; + mesg.MessageToolbarPane(); + + m_auimgr.AddPane( m_mainToolBar, + wxAuiPaneInfo( horiz ).Name( wxT( "m_mainToolBar" ) ).Top().Row( 0 ) ); + + m_auimgr.AddPane( m_drawToolBar, + wxAuiPaneInfo( vert ).Name( wxT( "m_VToolBar" ) ).Right() ); + + m_auimgr.AddPane( m_optionsToolBar, + wxAuiPaneInfo( vert ).Name( wxT( "m_optionsToolBar" ) ).Left() ); + + m_auimgr.AddPane( m_canvas, + wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() ); + + m_auimgr.AddPane( m_messagePanel, + wxAuiPaneInfo( mesg ).Name( wxT( "MsgPanel" ) ).Bottom().Layer(10) ); + + m_auimgr.Update(); + + Raise(); + Show( true ); + + wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED, ID_ZOOM_PAGE ); + wxPostEvent( this, evt ); +} + + +LIB_EDIT_FRAME::~LIB_EDIT_FRAME() +{ + m_drawItem = m_lastDrawItem = NULL; + + delete m_tempCopyComponent; + delete m_my_part; + m_my_part = NULL; + m_tempCopyComponent = NULL; +} + + +void LIB_EDIT_FRAME::SetDrawItem( LIB_ITEM* drawItem ) +{ + m_drawItem = drawItem; +} + + +void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) +{ + if( GetScreen()->IsModify() ) + { + int ii = DisplayExitDialog( this, _( "Save the changes in the library before closing?" ) ); + + switch( ii ) + { + case wxID_NO: + break; + + case wxID_YES: + if ( this->SaveActiveLibrary( false ) ) + break; + + // fall through: cancel the close because of an error + + case wxID_CANCEL: + Event.Veto(); + return; + } + GetScreen()->ClrModify(); + } + + PART_LIBS* libs = Prj().SchLibs(); + + BOOST_FOREACH( const PART_LIB& lib, *libs ) + { + if( lib.IsModified() ) + { + wxString msg = wxString::Format( _( + "Library '%s' was modified!\nDiscard changes?" ), + GetChars( lib.GetName() ) + ); + + if( !IsOK( this, msg ) ) + { + Event.Veto(); + return; + } + } + } + + Destroy(); +} + + +double LIB_EDIT_FRAME::BestZoom() +{ + /* Please, note: wxMSW before version 2.9 seems have + * problems with zoom values < 1 ( i.e. userscale > 1) and needs to be patched: + * edit file /src/msw/dc.cpp + * search for line static const int VIEWPORT_EXTENT = 1000; + * and replace by static const int VIEWPORT_EXTENT = 10000; + */ + int dx, dy; + + LIB_PART* part = GetCurPart(); + + if( part ) + { + EDA_RECT boundingBox = part->GetBoundingBox( m_unit, m_convert ); + + dx = boundingBox.GetWidth(); + dy = boundingBox.GetHeight(); + SetScrollCenterPosition( wxPoint( 0, 0 ) ); + } + else + { + const PAGE_INFO& pageInfo = GetScreen()->GetPageSettings(); + + dx = pageInfo.GetSizeIU().x; + dy = pageInfo.GetSizeIU().y; + + SetScrollCenterPosition( wxPoint( 0, 0 ) ); + } + + wxSize size = m_canvas->GetClientSize(); + + // Reserve a 10% margin around component bounding box. + double margin_scale_factor = 0.8; + double zx =(double) dx / ( margin_scale_factor * (double)size.x ); + double zy = (double) dy / ( margin_scale_factor * (double)size.y ); + + double bestzoom = std::max( zx, zy ); + + // keep it >= minimal existing zoom (can happen for very small components + // for instance when starting a new component + if( bestzoom < GetScreen()->m_ZoomList[0] ) + bestzoom = GetScreen()->m_ZoomList[0]; + + return bestzoom; +} + + +void LIB_EDIT_FRAME::UpdateAliasSelectList() +{ + if( m_aliasSelectBox == NULL ) + return; + + m_aliasSelectBox->Clear(); + + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + m_aliasSelectBox->Append( part->GetAliasNames() ); + m_aliasSelectBox->SetSelection( 0 ); + + int index = m_aliasSelectBox->FindString( m_aliasName ); + + if( index != wxNOT_FOUND ) + m_aliasSelectBox->SetSelection( index ); +} + + +void LIB_EDIT_FRAME::UpdatePartSelectList() +{ + if( m_partSelectBox == NULL ) + return; + + if( m_partSelectBox->GetCount() != 0 ) + m_partSelectBox->Clear(); + + LIB_PART* part = GetCurPart(); + + if( !part || part->GetUnitCount() <= 1 ) + { + m_unit = 1; + m_partSelectBox->Append( wxEmptyString ); + } + else + { + for( int i = 0; i < part->GetUnitCount(); i++ ) + { + wxString sub = LIB_PART::SubReference( i+1, false ); + wxString unit = wxString::Format( _( "Unit %s" ), GetChars( sub ) ); + m_partSelectBox->Append( unit ); + } + } + + // Ensure the current selected unit is compatible with + // the number of units of the current part: + if( part && part->GetUnitCount() < m_unit ) + m_unit = 1; + + m_partSelectBox->SetSelection( ( m_unit > 0 ) ? m_unit - 1 : 0 ); +} + + +void LIB_EDIT_FRAME::OnUpdateEditingPart( wxUpdateUIEvent& aEvent ) +{ + LIB_PART* part = GetCurPart(); + + aEvent.Enable( part != NULL ); + + if( part && aEvent.GetEventObject() == m_drawToolBar ) + aEvent.Check( GetToolId() == aEvent.GetId() ); +} + + +void LIB_EDIT_FRAME::OnUpdateNotEditingPart( wxUpdateUIEvent& event ) +{ + event.Enable( !GetCurPart() ); +} + + +void LIB_EDIT_FRAME::OnUpdateUndo( wxUpdateUIEvent& event ) +{ + event.Enable( GetCurPart() && GetScreen() && + GetScreen()->GetUndoCommandCount() != 0 && !IsEditingDrawItem() ); +} + + +void LIB_EDIT_FRAME::OnUpdateRedo( wxUpdateUIEvent& event ) +{ + event.Enable( GetCurPart() && GetScreen() && + GetScreen()->GetRedoCommandCount() != 0 && !IsEditingDrawItem() ); +} + + +void LIB_EDIT_FRAME::OnUpdateSaveCurrentLib( wxUpdateUIEvent& event ) +{ + PART_LIB* lib = GetCurLib(); + + event.Enable( lib && !lib->IsReadOnly() + && ( lib->IsModified() || GetScreen()->IsModify() ) ); +} + + +void LIB_EDIT_FRAME::OnUpdateViewDoc( wxUpdateUIEvent& event ) +{ + bool enable = false; + + PART_LIB* lib = GetCurLib(); + LIB_PART* part = GetCurPart(); + + if( part && lib ) + { + LIB_ALIAS* alias = part->GetAlias( m_aliasName ); + + wxCHECK_RET( alias != NULL, wxT( "Alias <" ) + m_aliasName + wxT( "> not found." ) ); + + enable = !alias->GetDocFileName().IsEmpty(); + } + + event.Enable( enable ); +} + + +void LIB_EDIT_FRAME::OnUpdatePinByPin( wxUpdateUIEvent& event ) +{ + LIB_PART* part = GetCurPart(); + + event.Enable( part && ( part->GetUnitCount() > 1 || m_showDeMorgan ) ); + + event.Check( m_editPinsPerPartOrConvert ); +} + +void LIB_EDIT_FRAME::OnUpdatePinTable( wxUpdateUIEvent& event ) +{ + LIB_PART* part = GetCurPart(); + event.Enable( part != NULL ); +} + +void LIB_EDIT_FRAME::OnUpdatePartNumber( wxUpdateUIEvent& event ) +{ + if( m_partSelectBox == NULL ) + return; + + LIB_PART* part = GetCurPart(); + + // Using the typical event.Enable() call doesn't seem to work with wxGTK + // so use the pointer to alias combobox to directly enable or disable. + m_partSelectBox->Enable( part && part->GetUnitCount() > 1 ); +} + + +void LIB_EDIT_FRAME::OnUpdateDeMorganNormal( wxUpdateUIEvent& event ) +{ + if( m_mainToolBar == NULL ) + return; + + LIB_PART* part = GetCurPart(); + + event.Enable( GetShowDeMorgan() || ( part && part->HasConversion() ) ); + event.Check( m_convert <= 1 ); +} + + +void LIB_EDIT_FRAME::OnUpdateDeMorganConvert( wxUpdateUIEvent& event ) +{ + if( m_mainToolBar == NULL ) + return; + + LIB_PART* part = GetCurPart(); + + event.Enable( GetShowDeMorgan() || ( part && part->HasConversion() ) ); + event.Check( m_convert > 1 ); +} + + +void LIB_EDIT_FRAME::OnUpdateSelectAlias( wxUpdateUIEvent& event ) +{ + if( m_aliasSelectBox == NULL ) + return; + + LIB_PART* part = GetCurPart(); + + // Using the typical event.Enable() call doesn't seem to work with wxGTK + // so use the pointer to alias combobox to directly enable or disable. + m_aliasSelectBox->Enable( part && part->GetAliasCount() > 1 ); +} + + +void LIB_EDIT_FRAME::OnSelectAlias( wxCommandEvent& event ) +{ + if( m_aliasSelectBox == NULL + || ( m_aliasSelectBox->GetStringSelection().CmpNoCase( m_aliasName ) == 0) ) + return; + + m_lastDrawItem = NULL; + m_aliasName = m_aliasSelectBox->GetStringSelection(); + + DisplayCmpDoc(); + m_canvas->Refresh(); +} + + +void LIB_EDIT_FRAME::OnSelectPart( wxCommandEvent& event ) +{ + int i = event.GetSelection(); + + if( ( i == wxNOT_FOUND ) || ( ( i + 1 ) == m_unit ) ) + return; + + m_lastDrawItem = NULL; + m_unit = i + 1; + m_canvas->Refresh(); + DisplayCmpDoc(); +} + + +void LIB_EDIT_FRAME::OnViewEntryDoc( wxCommandEvent& event ) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + wxString fileName; + LIB_ALIAS* alias = part->GetAlias( m_aliasName ); + + wxCHECK_RET( alias != NULL, wxT( "Alias not found." ) ); + + fileName = alias->GetDocFileName(); + + if( !fileName.IsEmpty() ) + { + SEARCH_STACK* lib_search = Prj().SchSearchS(); + + GetAssociatedDocument( this, fileName, lib_search ); + } +} + + +void LIB_EDIT_FRAME::OnSelectBodyStyle( wxCommandEvent& event ) +{ + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + if( event.GetId() == ID_DE_MORGAN_NORMAL_BUTT ) + m_convert = 1; + else + m_convert = 2; + + m_lastDrawItem = NULL; + m_canvas->Refresh(); +} + + +void LIB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) +{ + int id = event.GetId(); + wxPoint pos; + + m_canvas->SetIgnoreMouseEvents( true ); + + wxGetMousePosition( &pos.x, &pos.y ); + pos.y += 20; + + switch( id ) // Stop placement commands before handling new command. + { + case ID_POPUP_LIBEDIT_END_CREATE_ITEM: + case ID_LIBEDIT_EDIT_PIN: + case ID_POPUP_LIBEDIT_BODY_EDIT_ITEM: + case ID_POPUP_LIBEDIT_FIELD_EDIT_ITEM: + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM: + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM: + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM: + case ID_POPUP_ZOOM_BLOCK: + case ID_POPUP_DELETE_BLOCK: + case ID_POPUP_COPY_BLOCK: + case ID_POPUP_SELECT_ITEMS_BLOCK: + case ID_POPUP_MIRROR_X_BLOCK: + case ID_POPUP_MIRROR_Y_BLOCK: + case ID_POPUP_ROTATE_BLOCK: + case ID_POPUP_PLACE_BLOCK: + case ID_POPUP_LIBEDIT_DELETE_CURRENT_POLY_SEGMENT: + break; + + case ID_POPUP_LIBEDIT_CANCEL_EDITING: + if( m_canvas->IsMouseCaptured() ) + m_canvas->EndMouseCapture(); + else + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + break; + + case ID_POPUP_LIBEDIT_DELETE_ITEM: + m_canvas->EndMouseCapture(); + break; + + default: + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), + wxEmptyString ); + break; + } + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + switch( id ) + { + case ID_POPUP_LIBEDIT_CANCEL_EDITING: + break; + + case ID_LIBEDIT_SELECT_CURRENT_LIB: + SelectActiveLibrary(); + break; + + case ID_LIBEDIT_SAVE_CURRENT_PART: + { + LIB_PART* part = GetCurPart(); + + if( !part ) + { + DisplayError( this, _( "No part to save." ) ); + break; + } + + PART_LIB* lib = GetCurLib(); + + if( !lib ) + SelectActiveLibrary(); + + lib = GetCurLib(); + + if( !lib ) + { + DisplayError( this, _( "No library specified." ) ); + break; + } + + SaveOnePart( lib ); + } + break; + + case ID_LIBEDIT_EDIT_PIN_BY_PIN: + m_editPinsPerPartOrConvert = m_mainToolBar->GetToolToggled( ID_LIBEDIT_EDIT_PIN_BY_PIN ); + break; + + case ID_POPUP_LIBEDIT_END_CREATE_ITEM: + m_canvas->MoveCursorToCrossHair(); + if( m_drawItem ) + { + EndDrawGraphicItem( &dc ); + } + break; + + case ID_POPUP_LIBEDIT_BODY_EDIT_ITEM: + if( m_drawItem ) + { + m_canvas->CrossHairOff( &dc ); + + switch( m_drawItem->Type() ) + { + case LIB_ARC_T: + case LIB_CIRCLE_T: + case LIB_RECTANGLE_T: + case LIB_POLYLINE_T: + EditGraphicSymbol( &dc, m_drawItem ); + break; + + case LIB_TEXT_T: + EditSymbolText( &dc, m_drawItem ); + break; + + default: + ; + } + + m_canvas->CrossHairOn( &dc ); + } + break; + + case ID_POPUP_LIBEDIT_DELETE_CURRENT_POLY_SEGMENT: + { + // Delete the last created segment, while creating a polyline draw item + if( m_drawItem == NULL ) + break; + + m_canvas->MoveCursorToCrossHair(); + STATUS_FLAGS oldFlags = m_drawItem->GetFlags(); + m_drawItem->ClearFlags(); + m_drawItem->Draw( m_canvas, &dc, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, g_XorMode, NULL, + DefaultTransform ); + ( (LIB_POLYLINE*) m_drawItem )->DeleteSegment( GetCrossHairPosition( true ) ); + m_drawItem->Draw( m_canvas, &dc, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, g_XorMode, NULL, + DefaultTransform ); + m_drawItem->SetFlags( oldFlags ); + m_lastDrawItem = NULL; + } + break; + + case ID_POPUP_LIBEDIT_DELETE_ITEM: + if( m_drawItem ) + deleteItem( &dc ); + + break; + + case ID_POPUP_LIBEDIT_MOVE_ITEM_REQUEST: + if( m_drawItem == NULL ) + break; + + if( m_drawItem->Type() == LIB_PIN_T ) + StartMovePin( &dc ); + else + StartMoveDrawSymbol( &dc ); + break; + + case ID_POPUP_LIBEDIT_MODIFY_ITEM: + + if( m_drawItem == NULL ) + break; + + m_canvas->MoveCursorToCrossHair(); + if( m_drawItem->Type() == LIB_RECTANGLE_T + || m_drawItem->Type() == LIB_CIRCLE_T + || m_drawItem->Type() == LIB_POLYLINE_T + || m_drawItem->Type() == LIB_ARC_T + ) + { + StartModifyDrawSymbol( &dc ); + } + + break; + + case ID_POPUP_LIBEDIT_FIELD_EDIT_ITEM: + if( m_drawItem == NULL ) + break; + + m_canvas->CrossHairOff( &dc ); + + if( m_drawItem->Type() == LIB_FIELD_T ) + { + EditField( (LIB_FIELD*) m_drawItem ); + } + + m_canvas->MoveCursorToCrossHair(); + m_canvas->CrossHairOn( &dc ); + break; + + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM: + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM: + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM: + { + if( !m_drawItem || m_drawItem->Type() != LIB_PIN_T ) + break; + + LIB_PART* part = GetCurPart(); + + SaveCopyInUndoList( part ); + + GlobalSetPins( (LIB_PIN*) m_drawItem, id ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->Refresh(); + } + break; + + case ID_POPUP_ZOOM_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_ZOOM ); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_DELETE_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_DELETE ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_COPY_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_COPY ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + case ID_POPUP_SELECT_ITEMS_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_SELECT_ITEMS_ONLY ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_MIRROR_Y_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_MIRROR_Y ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + case ID_POPUP_MIRROR_X_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_MIRROR_X ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + case ID_POPUP_ROTATE_BLOCK: + m_canvas->SetAutoPanRequest( false ); + GetScreen()->m_BlockLocate.SetCommand( BLOCK_ROTATE ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + case ID_POPUP_PLACE_BLOCK: + m_canvas->SetAutoPanRequest( false ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + default: + DisplayError( this, wxT( "LIB_EDIT_FRAME::Process_Special_Functions error" ) ); + break; + } + + m_canvas->SetIgnoreMouseEvents( false ); + + if( GetToolId() == ID_NO_TOOL_SELECTED ) + m_lastDrawItem = NULL; +} + + +void LIB_EDIT_FRAME::OnActivate( wxActivateEvent& event ) +{ + EDA_DRAW_FRAME::OnActivate( event ); +} + + +PART_LIB* LIB_EDIT_FRAME::GetCurLib() +{ + wxString name = Prj().GetRString( PROJECT::SCH_LIBEDIT_CUR_LIB ); + + if( !!name ) + { + PART_LIB* lib = Prj().SchLibs()->FindLibrary( name ); + + if( !lib ) + Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString ); + + return lib; + } + + return NULL; +} + + +PART_LIB* LIB_EDIT_FRAME::SetCurLib( PART_LIB* aLib ) +{ + PART_LIB* old = GetCurLib(); + + if( !aLib || !aLib->GetName() ) + Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString ); + else + Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, aLib->GetName() ); + + return old; +} + + +LIB_PART* LIB_EDIT_FRAME::GetCurPart() +{ + if( !m_my_part ) + { + wxString name = Prj().GetRString( PROJECT::SCH_LIBEDIT_CUR_PART ); + LIB_PART* part; + + if( !!name && ( part = Prj().SchLibs()->FindLibPart( name ) ) ) + { + // clone it from the PART_LIB and own it. + m_my_part = new LIB_PART( *part ); + } + else + Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_PART, wxEmptyString ); + } + + return m_my_part; +} + + +void LIB_EDIT_FRAME::SetCurPart( LIB_PART* aPart ) +{ + delete m_my_part; + m_my_part = aPart; // take ownership here + + // retain in case this wxFrame is re-opened later on the same PROJECT + Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_PART, + aPart ? aPart->GetName() : wxString() ); +} + + +void LIB_EDIT_FRAME::TempCopyComponent() +{ + delete m_tempCopyComponent; + + if( LIB_PART* part = GetCurPart() ) + // clone it and own the clone. + m_tempCopyComponent = new LIB_PART( *part ); + else + // clear it, there was no CurPart + m_tempCopyComponent = NULL; +} + + +void LIB_EDIT_FRAME::RestoreComponent() +{ + if( m_tempCopyComponent ) + { + // transfer ownership to CurPart + SetCurPart( m_tempCopyComponent ); + m_tempCopyComponent = NULL; + } +} + + +void LIB_EDIT_FRAME::ClearTempCopyComponent() +{ + delete m_tempCopyComponent; + m_tempCopyComponent = NULL; +} + + +void LIB_EDIT_FRAME::EditSymbolText( wxDC* DC, LIB_ITEM* DrawItem ) +{ + if ( ( DrawItem == NULL ) || ( DrawItem->Type() != LIB_TEXT_T ) ) + return; + + // Deleting old text + if( DC && !DrawItem->InEditMode() ) + DrawItem->Draw( m_canvas, DC, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, g_XorMode, NULL, + DefaultTransform ); + + DIALOG_LIB_EDIT_TEXT* frame = new DIALOG_LIB_EDIT_TEXT( this, (LIB_TEXT*) DrawItem ); + frame->ShowModal(); + frame->Destroy(); + OnModify(); + + // Display new text + if( DC && !DrawItem->InEditMode() ) + DrawItem->Draw( m_canvas, DC, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, GR_DEFAULT_DRAWMODE, NULL, + DefaultTransform ); +} + + +void LIB_EDIT_FRAME::OnEditComponentProperties( wxCommandEvent& event ) +{ + bool partLocked = GetCurPart()->UnitsLocked(); + + DIALOG_EDIT_COMPONENT_IN_LIBRARY dlg( this ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + if( partLocked != GetCurPart()->UnitsLocked() ) + { + // m_editPinsPerPartOrConvert is set to the better value, if m_UnitSelectionLocked + // has changed + m_editPinsPerPartOrConvert = GetCurPart()->UnitsLocked() ? true : false; + } + + UpdateAliasSelectList(); + UpdatePartSelectList(); + DisplayLibInfos(); + DisplayCmpDoc(); + OnModify(); + m_canvas->Refresh(); +} + + +void LIB_EDIT_FRAME::OnCreateNewPartFromExisting( wxCommandEvent& event ) +{ + LIB_PART* part = GetCurPart(); + + wxCHECK_RET( part, wxT( "Cannot create new part from non-existent current part." ) ); + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + m_canvas->CrossHairOff( &dc ); + + EditField( &part->GetValueField() ); + + m_canvas->MoveCursorToCrossHair(); + m_canvas->CrossHairOn( &dc ); +} + + +void LIB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) +{ + int id = aEvent.GetId(); + + if( GetToolId() == ID_NO_TOOL_SELECTED ) + m_lastDrawItem = NULL; + + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), + wxEmptyString ); + + LIB_PART* part = GetCurPart(); + + switch( id ) + { + case ID_NO_TOOL_SELECTED: + SetToolID( id, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; + + case ID_LIBEDIT_PIN_BUTT: + if( part ) + { + SetToolID( id, wxCURSOR_PENCIL, _( "Add pin" ) ); + } + else + { + SetToolID( id, wxCURSOR_ARROW, _( "Set pin options" ) ); + + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + + cmd.SetId( ID_LIBEDIT_EDIT_PIN ); + GetEventHandler()->ProcessEvent( cmd ); + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + } + break; + + case ID_LIBEDIT_BODY_TEXT_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add text" ) ); + break; + + case ID_LIBEDIT_BODY_RECT_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add rectangle" ) ); + break; + + case ID_LIBEDIT_BODY_CIRCLE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add circle" ) ); + break; + + case ID_LIBEDIT_BODY_ARC_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add arc" ) ); + break; + + case ID_LIBEDIT_BODY_LINE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add line" ) ); + break; + + case ID_LIBEDIT_ANCHOR_ITEM_BUTT: + SetToolID( id, wxCURSOR_HAND, _( "Set anchor position" ) ); + break; + + case ID_LIBEDIT_IMPORT_BODY_BUTT: + SetToolID( id, m_canvas->GetDefaultCursor(), _( "Import" ) ); + LoadOneSymbol(); + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; + + case ID_LIBEDIT_EXPORT_BODY_BUTT: + SetToolID( id, m_canvas->GetDefaultCursor(), _( "Export" ) ); + SaveOneSymbol(); + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; + + case ID_LIBEDIT_DELETE_ITEM_BUTT: + if( !part ) + { + wxBell(); + break; + } + + SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) ); + break; + + default: + break; + } + + m_canvas->SetIgnoreMouseEvents( false ); +} + + +void LIB_EDIT_FRAME::OnRotateItem( wxCommandEvent& aEvent ) +{ + if( m_drawItem == NULL ) + return; + + if( !m_drawItem->InEditMode() ) + { + LIB_PART* part = GetCurPart(); + + SaveCopyInUndoList( part ); + m_drawItem->SetUnit( m_unit ); + } + + m_drawItem->Rotate(); + OnModify(); + + if( !m_drawItem->InEditMode() ) + m_drawItem->ClearFlags(); + + m_canvas->Refresh(); + + if( GetToolId() == ID_NO_TOOL_SELECTED ) + m_lastDrawItem = NULL; +} + + +LIB_ITEM* LIB_EDIT_FRAME::LocateItemUsingCursor( const wxPoint& aPosition, + const KICAD_T aFilterList[] ) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return NULL; + + LIB_ITEM* item = locateItem( aPosition, aFilterList ); + + wxPoint pos = GetNearestGridPosition( aPosition ); + + if( item == NULL && aPosition != pos ) + item = locateItem( pos, aFilterList ); + + return item; +} + + +LIB_ITEM* LIB_EDIT_FRAME::locateItem( const wxPoint& aPosition, const KICAD_T aFilterList[] ) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return NULL; + + LIB_ITEM* item = NULL; + + m_collectedItems.Collect( part->GetDrawItemList(), aFilterList, aPosition, + m_unit, m_convert ); + + if( m_collectedItems.GetCount() == 0 ) + { + ClearMsgPanel(); + } + else if( m_collectedItems.GetCount() == 1 ) + { + item = m_collectedItems[0]; + } + else + { + if( item == NULL ) + { + wxASSERT_MSG( m_collectedItems.GetCount() <= MAX_SELECT_ITEM_IDS, + wxT( "Select item clarification context menu size limit exceeded." ) ); + + wxMenu selectMenu; + wxMenuItem* title = new wxMenuItem( &selectMenu, wxID_NONE, _( "Clarify Selection" ) ); + + selectMenu.Append( title ); + selectMenu.AppendSeparator(); + + for( int i = 0; i < m_collectedItems.GetCount() && i < MAX_SELECT_ITEM_IDS; i++ ) + { + wxString text = m_collectedItems[i]->GetSelectMenuText(); + BITMAP_DEF xpm = m_collectedItems[i]->GetMenuImage(); + + AddMenuItem( &selectMenu, ID_SELECT_ITEM_START + i, text, KiBitmap( xpm ) ); + } + + // Set to NULL in case user aborts the clarification context menu. + m_drawItem = NULL; + m_canvas->SetAbortRequest( true ); // Changed to false if an item is selected + PopupMenu( &selectMenu ); + m_canvas->MoveCursorToCrossHair(); + item = m_drawItem; + } + } + + if( item ) + { + MSG_PANEL_ITEMS items; + item->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + } + else + { + ClearMsgPanel(); + } + + return item; +} + + +void LIB_EDIT_FRAME::deleteItem( wxDC* aDC ) +{ + wxCHECK_RET( m_drawItem != NULL, wxT( "No drawing item selected to delete." ) ); + + m_canvas->CrossHairOff( aDC ); + + LIB_PART* part = GetCurPart(); + + SaveCopyInUndoList( part ); + + if( m_drawItem->Type() == LIB_PIN_T ) + { + LIB_PIN* pin = (LIB_PIN*) m_drawItem; + wxPoint pos = pin->GetPosition(); + + part->RemoveDrawItem( (LIB_ITEM*) pin, m_canvas, aDC ); + + if( SynchronizePins() ) + { + LIB_PIN* tmp = part->GetNextPin(); + + while( tmp != NULL ) + { + pin = tmp; + tmp = part->GetNextPin( pin ); + + if( pin->GetPosition() != pos ) + continue; + + part->RemoveDrawItem( (LIB_ITEM*) pin ); + } + } + + m_canvas->Refresh(); + } + else + { + if( m_canvas->IsMouseCaptured() ) + { + m_canvas->CallEndMouseCapture( aDC ); + } + else + { + part->RemoveDrawItem( m_drawItem, m_canvas, aDC ); + m_canvas->Refresh(); + } + } + + m_drawItem = NULL; + m_lastDrawItem = NULL; + OnModify(); + m_canvas->CrossHairOn( aDC ); +} + + +void LIB_EDIT_FRAME::OnSelectItem( wxCommandEvent& aEvent ) +{ + int id = aEvent.GetId(); + int index = id - ID_SELECT_ITEM_START; + + if( (id >= ID_SELECT_ITEM_START && id <= ID_SELECT_ITEM_END) + && (index >= 0 && index < m_collectedItems.GetCount()) ) + { + LIB_ITEM* item = m_collectedItems[index]; + m_canvas->SetAbortRequest( false ); + m_drawItem = item; + } +} + +void LIB_EDIT_FRAME::OnOpenPinTable( wxCommandEvent& aEvent ) +{ + LIB_PART* part = GetCurPart(); + + DIALOG_LIB_EDIT_PIN_TABLE dlg( this, *part ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + return; +} + +bool LIB_EDIT_FRAME::SynchronizePins() +{ + LIB_PART* part = GetCurPart(); + + return !m_editPinsPerPartOrConvert && ( part && + ( part->HasConversion() || part->IsMulti() ) ); +} diff --git a/eeschema/libeditframe.h b/eeschema/libeditframe.h new file mode 100644 index 00000000..39648400 --- /dev/null +++ b/eeschema/libeditframe.h @@ -0,0 +1,678 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2014 Wayne Stambaugh + * Copyright (C) 2004-2014 KiCad Developers, see change_log.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 + */ + +/** + * @file libeditframe.h + * @brief Definition of class LIB_EDIT_FRAME + */ + +#ifndef LIBEDITFRM_H_ +#define LIBEDITFRM_H_ + +#include +#include + +#include +#include + + +class SCH_EDIT_FRAME; +class PART_LIB; +class LIB_PART; +class LIB_ALIAS; +class LIB_FIELD; +class DIALOG_LIB_EDIT_TEXT; + +/** + * The component library editor main window. + */ +class LIB_EDIT_FRAME : public SCH_BASE_FRAME +{ + LIB_PART* m_my_part; ///< a part I own, it is not in any library, but a copy could be. + LIB_PART* m_tempCopyComponent; ///< temp copy of a part during edit, I own it here. + LIB_COLLECTOR m_collectedItems; ///< Used for hit testing. + wxComboBox* m_partSelectBox; ///< a Box to select a part to edit (if any) + wxComboBox* m_aliasSelectBox; ///< a box to select the alias to edit (if any) + + /** Convert of the item currently being drawn. */ + bool m_drawSpecificConvert; + + /** + * Specify which component parts the current draw item applies to. + * + * If true, the item being drawn or edited applies only to the selected + * part. Otherwise it applies to all parts in the component. + */ + bool m_drawSpecificUnit; + + /** + * Set to true to not synchronize pins at the same position when editing + * components with multiple parts or multiple body styles. Setting this + * to false allows editing each pin per part or body style individually. + * This requires the user to open each part or body style to make changes + * to the pin at the same location. + */ + bool m_editPinsPerPartOrConvert; + + /** The current draw or edit graphic item fill style. */ + static FILL_T m_drawFillStyle; + + /** Default line width for drawing or editing graphic items. */ + static int m_drawLineWidth; + + static LIB_ITEM* m_lastDrawItem; + static LIB_ITEM* m_drawItem; + static wxString m_aliasName; + + // The unit number to edit and show + static int m_unit; + + // Show the normal shape ( m_convert <= 1 ) or the converted shape + // ( m_convert > 1 ) + static int m_convert; + + // true to force DeMorgan/normal tools selection enabled. + // They are enabled when the loaded component has + // Graphic items for converted shape + // But under some circumstances (New component created) + // these tools must left enabled + static bool m_showDeMorgan; + + /// The current text size setting. + static int m_textSize; + + /// Current text orientation setting. + static int m_textOrientation; + + /// The default pin num text size setting. + static int m_textPinNumDefaultSize; + + /// The default pin name text size setting. + static int m_textPinNameDefaultSize; + + /// Default pin length + static int m_defaultPinLength; + + /// Default repeat offset for pins in repeat place pin + int m_repeatPinStep; + + static wxSize m_clientSize; + + friend class DIALOG_LIB_EDIT_TEXT; + + LIB_ITEM* locateItem( const wxPoint& aPosition, const KICAD_T aFilterList[] ); + +public: + + LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); + + ~LIB_EDIT_FRAME(); + + /** The current library being edited, or NULL if none. */ + PART_LIB* GetCurLib(); + + /** Sets the current library and return the old. */ + PART_LIB* SetCurLib( PART_LIB* aLib ); + + /** + * Function GetCurPart + * returns the current part being edited, or NULL if none selected. + * This is a LIB_PART that I own, it is at best a copy of one in a library. + */ + LIB_PART* GetCurPart(); + + /** + * Function SetCurPart + * takes ownership over aPart and notes that it is the one currently + * being edited. + */ + void SetCurPart( LIB_PART* aPart ); + + /** @return the default pin num text size. + */ + static int GetPinNumDefaultSize() { return m_textPinNumDefaultSize; } + + /** @return The default pin name text size setting. + */ + static int GetPinNameDefaultSize() { return m_textPinNameDefaultSize; } + + /** @return The default pin len setting. + */ + static int GetDefaultPinLength() { return m_defaultPinLength; } + + /** Set the default pin len. + */ + static void SetDefaultPinLength( int aLength ) { m_defaultPinLength = aLength; } + + /** + * @return the increment value of the position of a pin + * for the pin repeat command + */ + int GetRepeatPinStep() const { return m_repeatPinStep; } + + /** + * Sets the repeat step value for pins repeat command + * @param aStep the increment value of the position of an item + * for the repeat command + */ + void SetRepeatPinStep( int aStep) { m_repeatPinStep = aStep; } + + + void ReCreateMenuBar(); + + /** + * Function EnsureActiveLibExists + * must be called after the libraries are reloaded + * (for instance after loading a schematic project) + */ + static void EnsureActiveLibExists(); + + void InstallConfigFrame( wxCommandEvent& event ); + void OnColorConfig( wxCommandEvent& aEvent ); + void OnPreferencesOptions( wxCommandEvent& event ); + void Process_Config( wxCommandEvent& event ); + + /** + * Function SycnronizePins + * @return True if the edit pins per part or convert is false and the current + * component has multiple parts or body styles. Otherwise false is + * returned. + */ + bool SynchronizePins(); + + /** + * Function OnPlotCurrentComponent + * plot the current component in SVG or PNG format. + */ + void OnPlotCurrentComponent( wxCommandEvent& event ); + void Process_Special_Functions( wxCommandEvent& event ); + void OnSelectTool( wxCommandEvent& aEvent ); + + /** + * Routine to read one part. + * The format is that of libraries, but it loads only 1 component. + * Or 1 component if there are several. + * If the first component is an alias, it will load the corresponding root. + */ + void OnImportPart( wxCommandEvent& event ); + + /** + * Function OnExportPart + * creates a new library and backup the current component in this library or export + * the component of the current library. + */ + void OnExportPart( wxCommandEvent& event ); + void OnSelectAlias( wxCommandEvent& event ); + void OnSelectPart( wxCommandEvent& event ); + + /** + * Function DeleteOnePart + * is the command event handler to delete an entry from the current library. + * + * The deleted entry can be an alias or a component. If the entry is an alias, + * it is removed from the component and the list of alias is updated. If the + * entry is a component and the list of aliases is empty, the component and all + * it drawable items are deleted. Otherwise the first alias in the alias list + * becomes the new component name and the other aliases become dependent on + * renamed component. + * + * @note This only deletes the entry in memory. The file does not change. + */ + void DeleteOnePart( wxCommandEvent& event ); + + /** + * Function CreateNewLibraryPart + * is the command event handler to create a new library component. + * + * If an old component is currently in edit, it is deleted. + */ + void CreateNewLibraryPart( wxCommandEvent& event ); + + void OnCreateNewPartFromExisting( wxCommandEvent& event ); + void OnEditComponentProperties( wxCommandEvent& event ); + void InstallFieldsEditorDialog( wxCommandEvent& event ); + + /** + * Function LoadOneLibraryPart + * loads a library component from the currently selected library. + * + * If a library is already selected, the user is prompted for the component name + * to load. If there is no current selected library, the user is prompted to select + * a library name and then select component to load. + */ + void LoadOneLibraryPart( wxCommandEvent& event ); + + void OnViewEntryDoc( wxCommandEvent& event ); + void OnCheckComponent( wxCommandEvent& event ); + void OnSelectBodyStyle( wxCommandEvent& event ); + void OnEditPin( wxCommandEvent& event ); + void OnSelectItem( wxCommandEvent& aEvent ); + + void OnOpenPinTable( wxCommandEvent& aEvent ); + + void OnUpdateSelectTool( wxUpdateUIEvent& aEvent ); + void OnUpdateEditingPart( wxUpdateUIEvent& event ); + void OnUpdateNotEditingPart( wxUpdateUIEvent& event ); + void OnUpdateUndo( wxUpdateUIEvent& event ); + void OnUpdateRedo( wxUpdateUIEvent& event ); + void OnUpdateSaveCurrentLib( wxUpdateUIEvent& event ); + void OnUpdateViewDoc( wxUpdateUIEvent& event ); + void OnUpdatePinByPin( wxUpdateUIEvent& event ); + void OnUpdatePinTable( wxUpdateUIEvent& event ); + void OnUpdatePartNumber( wxUpdateUIEvent& event ); + void OnUpdateDeMorganNormal( wxUpdateUIEvent& event ); + void OnUpdateDeMorganConvert( wxUpdateUIEvent& event ); + void OnUpdateSelectAlias( wxUpdateUIEvent& event ); + + void UpdateAliasSelectList(); + void UpdatePartSelectList(); + + /** + * Function DisplayLibInfos + * updates the main window title bar with the current library name and read only status + * of the library. + */ + void DisplayLibInfos(); + + /** + * Function RedrawComponent + * Redraw the current component loaded in library editor + * Display reference like in schematic (a reference U is shown U? or U?A) + * accordint to the current selected unit and De Morgan selection + * although it is stored without ? and part id. + * @param aDC = the current device context + * @param aOffset = a draw offset. usually 0,0 to draw on the screen, but + * can be set to page size / 2 to draw or print in SVG format. + */ + void RedrawComponent( wxDC* aDC, wxPoint aOffset ); + + /** + * Function RedrawActiveWindow + * Redraw the current component loaded in library editor, an axes + * Display reference like in schematic (a reference U is shown U? or U?A) + * update status bar and info shown in the bottom of the window + */ + void RedrawActiveWindow( wxDC* DC, bool EraseBg ); + + void OnCloseWindow( wxCloseEvent& Event ); + void ReCreateHToolbar(); + void ReCreateVToolbar(); + void CreateOptionToolbar(); + void OnLeftClick( wxDC* DC, const wxPoint& MousePos ); + bool OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ); + double BestZoom(); // Returns the best zoom + void OnLeftDClick( wxDC* DC, const wxPoint& MousePos ); + + ///> @copydoc EDA_DRAW_FRAME::GetHotKeyDescription() + EDA_HOTKEY* GetHotKeyDescription( int aCommand ) const; + + bool OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem = NULL ); + + bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); + + void LoadSettings( wxConfigBase* aCfg ); + + void SaveSettings( wxConfigBase* aCfg ); + + /** + * Function CloseWindow + * triggers the wxCloseEvent, which is handled by the function given + * to EVT_CLOSE() macro: + *

      + * EVT_CLOSE( LIB_EDIT_FRAME::OnCloseWindow ) + */ + void CloseWindow( wxCommandEvent& event ) + { + // Generate a wxCloseEvent + Close( false ); + } + + /** + * Function OnModify + * Must be called after a schematic change + * in order to set the "modify" flag of the current screen + */ + void OnModify() + { + GetScreen()->SetModify(); + } + + const wxString& GetAliasName() { return m_aliasName; } + + int GetUnit() { return m_unit; } + + void SetUnit( int unit ) + { + wxASSERT( unit >= 1 ); + m_unit = unit; + } + + int GetConvert() { return m_convert; } + + void SetConvert( int convert ) + { + wxASSERT( convert >= 0 ); + m_convert = convert; + } + + LIB_ITEM* GetLastDrawItem() { return m_lastDrawItem; } + + void SetLastDrawItem( LIB_ITEM* drawItem ) + { + m_lastDrawItem = drawItem; + } + + LIB_ITEM* GetDrawItem() { return m_drawItem; } + + void SetDrawItem( LIB_ITEM* drawItem ); + + bool GetShowDeMorgan() { return m_showDeMorgan; } + + void SetShowDeMorgan( bool show ) { m_showDeMorgan = show; } + + FILL_T GetFillStyle() { return m_drawFillStyle; } + + /** + * Function TempCopyComponent + * create a temporary copy of the current edited component + * Used to prepare an Undo ant/or abort command before editing the component + */ + void TempCopyComponent(); + + /** + * Function RestoreComponent + * Restore the current edited component from its temporary copy. + * Used to abort a command + */ + void RestoreComponent(); + + /** + * Function GetTempCopyComponent + * @return the temporary copy of the current component. + */ + LIB_PART* GetTempCopyComponent() { return m_tempCopyComponent; } + + /** + * Function ClearTempCopyComponent + * delete temporary copy of the current component and clear pointer + */ + void ClearTempCopyComponent(); + + bool IsEditingDrawItem() { return m_drawItem && m_drawItem->InEditMode(); } + +private: + + /** + * Function OnActivate + * is called when the frame is activated. Tests if the current library exists. + * The library list can be changed by the schematic editor after reloading a new schematic + * and the current library can point a non existent lib. + */ + virtual void OnActivate( wxActivateEvent& event ); + + // General: + + /** + * Function SaveOnePart + * saves the current LIB_PART into the provided PART_LIB. + * + * Any changes are updated in memory only and NOT to a file. The old component is + * deleted from the library and/or any aliases before the edited component is updated + * in the library. + * @param aLib - the part library where the part must be saved. + * @param aPromptUser true to ask for confirmation, when the part_lib is already existing + * in memory, false to save silently + * @return true if the part was saved, false if aborted by user + */ + bool SaveOnePart( PART_LIB* aLib, bool aPromptUser = true ); + + /** + * Function SelectActiveLibrary + * sets the current active library to \a aLibrary. + * + * @param aLibrary A pointer to the PART_LIB object to select. If NULL, then display + * list of available libraries to select from. + */ + void SelectActiveLibrary( PART_LIB* aLibrary = NULL ); + + /** + * Function OnSaveActiveLibrary + * it the command event handler to save the changes to the current library. + * + * A backup file of the current library is saved with the .bak extension before the + * changes made to the library are saved. + */ + void OnSaveActiveLibrary( wxCommandEvent& event ); + + /** + * Function SaveActiveLibrary + * saves the changes to the current library. + * + * A backup file of the current library is saved with the .bak extension before the + * changes made to the library are saved. + * @param newFile Ask for a new file name to save the library. + * @return True if the library was successfully saved. + */ + bool SaveActiveLibrary( bool newFile ); + + /** + * Function LoadComponentFromCurrentLib + * loads a component from the current active library. + * @param aLibEntry The component to load from \a aLibrary (can be an alias) + * @return true if \a aLibEntry loaded correctly. + */ + bool LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry ); + + /** + * Function LoadOneLibraryPartAux + * loads a copy of \a aLibEntry from \a aLibrary into memory. + * + * @param aLibEntry A pointer to the LIB_ALIAS object to load. + * @param aLibrary A pointer to the PART_LIB object to load \a aLibEntry from. + * @return True if a copy of \a aLibEntry was successfully loaded from \a aLibrary. + */ + bool LoadOneLibraryPartAux( LIB_ALIAS* aLibEntry, PART_LIB* aLibrary ); + + /** + * Function DisplayCmpDoc + * displays the documentation of the selected component. + */ + void DisplayCmpDoc(); + + /** + * Function OnRotateItem + * rotates the current item. + */ + void OnRotateItem( wxCommandEvent& aEvent ); + + /** + * Function deleteItem + * deletes the currently selected draw item. + * @param aDC The device context to draw upon when removing item. + */ + void deleteItem( wxDC* aDC ); + + // General editing +public: + /** + * Function SaveCopyInUndoList. + * Create a copy of the current component, and save it in the undo list. + * Because a component in library editor does not a lot of primitives, + * the full data is duplicated. It is not worth to try to optimize this save funtion + */ + void SaveCopyInUndoList( EDA_ITEM* ItemToCopy ); + +private: + void GetComponentFromUndoList( wxCommandEvent& event ); + void GetComponentFromRedoList( wxCommandEvent& event ); + + // Editing pins + void CreatePin( wxDC* DC ); + void StartMovePin( wxDC* DC ); + + /** + * Function CreateImagePins + * adds copies of \a aPin for \a aUnit in components with multiple parts and + * \a aConvert for components that have multiple body styles. + * + * @param aPin The pin to copy. + * @param aUnit The unit to add a copy of \a aPin to. + * @param aConvert The alternate body style to add a copy of \a aPin to. + * @param aDeMorgan Flag to indicate if \a aPin should be created for the + * alternate body style. + */ + void CreateImagePins( LIB_PIN* aPin, int aUnit, int aConvert, bool aDeMorgan ); + + /** + * Function PlaceAnchor + * places an anchor reference coordinate for the current component. + *

      + * All object coordinates are offset to the current cursor position. + *

      + */ + void PlaceAnchor(); + + // Editing graphic items + LIB_ITEM* CreateGraphicItem( LIB_PART* LibEntry, wxDC* DC ); + void GraphicItemBeginDraw( wxDC* DC ); + void StartMoveDrawSymbol( wxDC* DC ); + void StartModifyDrawSymbol( wxDC* DC ); // + * A symbol file *.sym has the same format as a library, and contains only + * one symbol. + *

      + */ + void LoadOneSymbol(); + + /** + * Function SaveOneSymbol + * saves the current component to a symbol file. + *

      + * The symbol file format is similar to the standard component library file format, but + * there is only one symbol. Invisible pins are not saved. + */ + void SaveOneSymbol(); + + void EditGraphicSymbol( wxDC* DC, LIB_ITEM* DrawItem ); + void EditSymbolText( wxDC* DC, LIB_ITEM* DrawItem ); + LIB_ITEM* LocateItemUsingCursor( const wxPoint& aPosition, + const KICAD_T aFilterList[] = LIB_COLLECTOR::AllItems ); + void EditField( LIB_FIELD* Field ); + +public: + /** + * Function LoadComponentAndSelectLib + * selects the current active library. + * + * @param aLibrary The PART_LIB to select + * @param aLibEntry The component to load from aLibrary (can be an alias). + * @return true if \a aLibEntry was loaded from \a aLibrary. + */ + bool LoadComponentAndSelectLib( LIB_ALIAS* aLibEntry, PART_LIB* aLibrary ); + + /* Block commands: */ + + /** + * Function BlockCommand + * returns the block command (BLOCK_MOVE, BLOCK_COPY...) corresponding to + * the \a aKey (ALT, SHIFT ALT ..) + */ + virtual int BlockCommand( int aKey ); + + /** + * Function HandleBlockPlace + * handles the block place command. + */ + virtual void HandleBlockPlace( wxDC* DC ); + + /** + * Function HandleBlockEnd + * performs a block end command. + * @return If command finished (zoom, delete ...) false is returned otherwise true + * is returned indicating more processing is required. + */ + virtual bool HandleBlockEnd( wxDC* DC ); + + /** + * Function PlacePin + * Place at cursor location the pin currently moved (i.e. pin pointed by m_drawItem) + * (and the linked pins, if any) + */ + void PlacePin(); + + /** + * Function GlobalSetPins + * @param aMasterPin is the "template" pin + * @param aId is a param to select what should be mofified: + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM: + * Change pins text name size + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM: + * Change pins text num size + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM: + * Change pins length. + * + * If aMasterPin is selected ( .m_flag == IS_SELECTED ), + * only the other selected pins are modified + */ + void GlobalSetPins( LIB_PIN* aMasterPin, int aId ); + + // Automatic placement of pins + void RepeatPinItem( wxDC* DC, LIB_PIN* Pin ); + + /** + * Function CreatePNGorJPEGFile + * creates an image (screenshot) of the current component in PNG or JPEG format. + * @param aFileName = the full filename + * @param aFmt_jpeg = true to use JPEG file format, false to use PNG file format + */ + void CreatePNGorJPEGFile( const wxString& aFileName, bool aFmt_jpeg ); + + /** + * Virtual function PrintPage + * used to print a page + * @param aDC = wxDC given by the calling print function + * @param aPrintMask = not used here + * @param aPrintMirrorMode = not used here (Set when printing in mirror mode) + * @param aData = a pointer on an auxiliary data (not always used, NULL if not used) + */ + virtual void PrintPage( wxDC* aDC, LSET aPrintMask, + bool aPrintMirrorMode, void* aData = NULL ); + + /** + * Function SVG_PlotComponent + * Creates the SVG print file for the current edited component. + * @param aFullFileName = the full filename + */ + void SVG_PlotComponent( const wxString& aFullFileName ); + + DECLARE_EVENT_TABLE() +}; + +#endif // LIBEDITFRM_H_ diff --git a/eeschema/libfield.cpp b/eeschema/libfield.cpp new file mode 100644 index 00000000..df3438ce --- /dev/null +++ b/eeschema/libfield.cpp @@ -0,0 +1,161 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2007-2016 KiCad Developers, see CHANGELOG.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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +void LIB_EDIT_FRAME::EditField( LIB_FIELD* aField ) +{ + wxString newFieldValue; + wxString title; + wxString caption; + wxString oldName; + + if( aField == NULL ) + return; + + LIB_PART* parent = aField->GetParent(); + + wxASSERT( parent ); + + // Editing the component value field is equivalent to creating a new component based + // on the current component. Set the dialog message to inform the user. + if( aField->GetId() == VALUE ) + { + caption = _( "Component Name" ); + title = _( "Enter a name to create a new component based on this one." ); + } + else + { + caption.Printf( _( "Edit Field %s" ), GetChars( aField->GetName() ) ); + title.Printf( _( "Enter a new value for the %s field." ), + GetChars( aField->GetName().Lower() ) ); + } + + DIALOG_LIB_EDIT_ONE_FIELD dlg( this, caption, aField ); + + // The dialog may invoke a kiway player for footprint fields + // so we must use a quasimodal dialog. + if( dlg.ShowQuasiModal() != wxID_OK ) + return; + + newFieldValue = dlg.GetText(); + wxString fieldText = aField->GetFullText( m_unit ); + + /* If the value field is changed, this is equivalent to creating a new component from + * the old one. Rename the component and remove any conflicting aliases to prevent name + * errors when updating the library. + */ + if( aField->GetId() == VALUE && newFieldValue != aField->GetText() ) + { + wxString msg; + + PART_LIB* lib = GetCurLib(); + + // Test the current library for name conflicts. + if( lib && lib->FindEntry( newFieldValue ) ) + { + msg.Printf( _( + "The name '%s' conflicts with an existing entry in the component library '%s'.\n\n" + "Do you wish to replace the current component in the library with this one?" ), + GetChars( newFieldValue ), + GetChars( lib->GetName() ) + ); + + int rsp = wxMessageBox( msg, _( "Confirm" ), + wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT, this ); + + if( rsp == wxNO ) + return; + } + + // Test the current component for name conflicts. + if( parent->HasAlias( newFieldValue ) ) + { + msg.Printf( _( "The current component already has an alias named '%s'.\n\n" + "Do you wish to remove this alias from the component?" ), + GetChars( newFieldValue ) ); + + int rsp = wxMessageBox( msg, _( "Confirm" ), wxYES_NO | wxICON_QUESTION, this ); + + if( rsp == wxNO ) + return; + + parent->RemoveAlias( newFieldValue ); + } + + parent->SetName( newFieldValue ); + + // Test the library for any conflicts with the any aliases in the current component. + if( parent->GetAliasCount() > 1 && lib && lib->Conflicts( parent ) ) + { + msg.Printf( _( + "The new component contains alias names that conflict with entries in the " + "component library '%s'.\n\n" + "Do you wish to remove all of the conflicting aliases from this component?" ), + GetChars( lib->GetName() ) + ); + + int rsp = wxMessageBox( msg, _( "Confirm" ), wxYES_NO | wxICON_QUESTION, this ); + + if( rsp == wxNO ) + { + parent->SetName( fieldText ); + return; + } + + wxArrayString aliases = parent->GetAliasNames( false ); + + for( size_t i = 0; i < aliases.GetCount(); i++ ) + { + if( lib->FindEntry( aliases[ i ] ) != NULL ) + parent->RemoveAlias( aliases[ i ] ); + } + } + + if( !parent->HasAlias( m_aliasName ) ) + m_aliasName = newFieldValue; + } + + dlg.UpdateField( aField ); + + if( !aField->InEditMode() ) + SaveCopyInUndoList( parent ); + + m_canvas->Refresh(); + + OnModify(); + UpdateAliasSelectList(); +} diff --git a/eeschema/load_one_schematic_file.cpp b/eeschema/load_one_schematic_file.cpp new file mode 100644 index 00000000..5d4e3458 --- /dev/null +++ b/eeschema/load_one_schematic_file.cpp @@ -0,0 +1,413 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr + * Copyright (C) 2008 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file load_one_schematic_file.cpp + * @brief Code to load and save Eeschema files. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +bool ReadSchemaDescr( LINE_READER* aLine, wxString& aMsgDiag, SCH_SCREEN* Window ); + + +bool SCH_EDIT_FRAME::LoadOneEEFile( SCH_SCREEN* aScreen, const wxString& aFullFileName, bool append ) +{ + char name1[256]; + bool itemLoaded = false; + SCH_ITEM* item; + wxString msgDiag; // Error and log messages + char* line; + wxFileName fn; + + if( aScreen == NULL ) + return false; + + if( aFullFileName.IsEmpty() ) + return false; + + // Place the undo limit into the screen + aScreen->SetMaxUndoItems( m_UndoRedoCountMax ); + + // If path is relative, this expands it from the project directory. + wxString fname = Prj().AbsolutePath( aFullFileName ); + +#ifdef __WINDOWS__ + fname.Replace( wxT("/"), wxT("\\") ); +#else + fname.Replace( wxT("\\"), wxT("/") ); +#endif + + fn = fname; + CheckForAutoSaveFile( fn, SchematicBackupFileExtension ); + + wxLogTrace( traceAutoSave, wxT( "Loading schematic file " ) + aFullFileName ); + + aScreen->SetCurItem( NULL ); + if( !append ) + aScreen->SetFileName( aFullFileName ); + + FILE* f = wxFopen( fname, wxT( "rt" ) ); + + if( !f ) + { + msgDiag.Printf( _( "Failed to open '%s'" ), GetChars( aFullFileName ) ); + DisplayError( this, msgDiag ); + return false; + } + + // reader now owns the open FILE. + FILE_LINE_READER reader( f, aFullFileName ); + + msgDiag.Printf( _( "Loading '%s'" ), GetChars( aScreen->GetFileName() ) ); + PrintMsg( msgDiag ); + + if( !reader.ReadLine() + || strncmp( (char*)reader + 9, SCHEMATIC_HEAD_STRING, + sizeof( SCHEMATIC_HEAD_STRING ) - 1 ) != 0 ) + { + msgDiag.Printf( _( "'%s' is NOT an Eeschema file!" ), GetChars( aFullFileName ) ); + DisplayError( this, msgDiag ); + return false; + } + + line = reader.Line(); + + // get the file version here. + char *strversion = line + 9 + sizeof( SCHEMATIC_HEAD_STRING ); + + // Skip blanks + while( *strversion && *strversion < '0' ) + strversion++; + + int version = atoi( strversion ); + + if( version > EESCHEMA_VERSION ) + { + msgDiag.Printf( _( + "'%s' was created by a more recent version of Eeschema and may not" + " load correctly. Please consider updating!" ), + GetChars( aFullFileName ) + ); + DisplayInfoMessage( this, msgDiag ); + } + +#if 0 + // Compile it if the new version is unreadable by previous Eeschema versions + else if( version < EESCHEMA_VERSION ) + { + MsgDiag = aFullFileName + _( " was created by an older version of \ +Eeschema. It will be stored in the new file format when you save this file \ +again." ); + + DisplayInfoMessage( this, MsgDiag ); + } +#endif + + // The next lines are the lib list section, and are mainly comments, like: + // LIBS:power + // the lib list is not used, but is in schematic file just in case. + // It is usually not empty, but we accept empty list. + // If empty, there is a legacy section, not used + // EELAYER i j + // and the last line is + // EELAYER END + // Skip all lines until the end of header "EELAYER END" is found + while( reader.ReadLine() ) + { + line = reader.Line(); + + while( *line == ' ' ) + line++; + + if( strnicmp( line, "EELAYER END", 11 ) == 0 ) + break; // end of not used header found + } + + while( reader.ReadLine() ) + { + itemLoaded = false; + line = reader.Line(); + + item = NULL; + + char* sline = line; + + while( (*sline != ' ' ) && *sline ) + sline++; + + switch( line[0] ) + { + case '$': // identification block + if( line[1] == 'C' ) + item = new SCH_COMPONENT(); + else if( line[1] == 'S' ) + item = new SCH_SHEET(); + else if( line[1] == 'D' ) + itemLoaded = ReadSchemaDescr( &reader, msgDiag, aScreen ); + else if( line[1] == 'B' ) + item = new SCH_BITMAP(); + else if( line[1] == 'E' ) + itemLoaded = true; // The EOF marker + break; + + case 'L': // Its a library item. + item = new SCH_COMPONENT(); + break; + + case 'W': // Its a Segment (WIRE or BUS) item. + item = new SCH_LINE(); + break; + + case 'E': // Its a WIRE or BUS item. + /* The bus entry can be represented by two different + * classes, so we need a factory function */ + itemLoaded = SCH_BUS_ENTRY_BASE::Load( reader, msgDiag, &item ); + break; + + case 'C': // It is a connection item. + item = new SCH_JUNCTION(); + break; + + case 'K': // It is a Marker item. + // Markers are no more read from file. they are only created on + // demand in schematic + itemLoaded = true; // Just skip descr and disable err message + break; + + case 'N': // It is a NoConnect item. + item = new SCH_NO_CONNECT(); + break; + + case 'T': // It is a text item. + if( sscanf( sline, "%255s", name1 ) != 1 ) + { + msgDiag.Printf( _( "Eeschema file text load error at line %d" ), + reader.LineNumber() ); + itemLoaded = false; + } + else if( name1[0] == 'L' ) + item = new SCH_LABEL(); + else if( name1[0] == 'G' && version > 1 ) + item = new SCH_GLOBALLABEL(); + else if( (name1[0] == 'H') || (name1[0] == 'G' && version == 1) ) + item = new SCH_HIERLABEL(); + else + item = new SCH_TEXT(); + break; + + default: + itemLoaded = false; + msgDiag.Printf( _( "Eeschema file undefined object at line %d, aborted" ), + reader.LineNumber() ); + msgDiag << wxT( "\n" ) << FROM_UTF8( line ); + } + + if( item ) + { + // Load it if it wasn't by a factory + if( !itemLoaded ) + itemLoaded = item->Load( reader, msgDiag ); + + if( !itemLoaded ) + { + delete item; + } + else + { + aScreen->Append( item ); + } + } + + if( !itemLoaded ) + { + msgDiag.Printf( _( "Eeschema file object not loaded at line %d, aborted" ), + reader.LineNumber() ); + msgDiag << wxT( "\n" ) << FROM_UTF8( line ); + DisplayError( this, msgDiag ); + break; + } + } + +#if 0 && defined (DEBUG) + aScreen->Show( 0, std::cout ); +#endif + + // Build links between each components and its part lib LIB_PART + aScreen->CheckComponentsToPartsLinks(); + + aScreen->TestDanglingEnds(); + + msgDiag.Printf( _( "Done Loading <%s>" ), GetChars( aScreen->GetFileName() ) ); + PrintMsg( msgDiag ); + + return true; // Although it may be that file is only partially loaded. +} + + +/// Get the length of a string constant, at compile time +#define SZ( x ) (sizeof(x)-1) + +static const char delims[] = " \t\r\n"; + +/* Read the schematic header. */ +bool ReadSchemaDescr( LINE_READER* aLine, wxString& aMsgDiag, SCH_SCREEN* aScreen ) +{ + char* line = aLine->Line(); + + char* pageType = strtok( line + SZ( "$Descr" ), delims ); + char* width = strtok( NULL, delims ); + char* height = strtok( NULL, delims ); + char* orient = strtok( NULL, delims ); + + wxString pagename = FROM_UTF8( pageType ); + + PAGE_INFO pageInfo; + TITLE_BLOCK tb; + + if( !pageInfo.SetType( pagename ) ) + { + aMsgDiag.Printf( _( "Eeschema file dimension definition error line %d," + "\nAbort reading file.\n" ), + aLine->LineNumber() ); + aMsgDiag << FROM_UTF8( line ); + } + + if( pagename == PAGE_INFO::Custom ) + { + if( width && height ) + { + int w = atoi( width ); + int h = atoi( height ); + + pageInfo.SetWidthMils( w ); + pageInfo.SetHeightMils( h ); + } + } + + // non custom size, set portrait if its present + else if( orient && !strcmp( orient, "portrait" ) ) + { + pageInfo.SetPortrait( true ); + } + + aScreen->SetPageSettings( pageInfo ); + + for(;;) + { + char buf[1024]; + + if( !aLine->ReadLine() ) + return true; + + line = aLine->Line(); + + if( strnicmp( line, "$End", 4 ) == 0 ) + { + aScreen->SetTitleBlock( tb ); + break; + } + + if( strnicmp( line, "Sheet", 2 ) == 0 ) + sscanf( line + 5, " %d %d", + &aScreen->m_ScreenNumber, &aScreen->m_NumberOfScreens ); + + if( strnicmp( line, "Title", 2 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetTitle( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Date", 2 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetDate( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Rev", 2 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetRevision( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Comp", 4 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetCompany( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Comment1", 8 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetComment1( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Comment2", 8 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetComment2( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Comment3", 8 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetComment3( FROM_UTF8( buf ) ); + continue; + } + + if( strnicmp( line, "Comment4", 8 ) == 0 ) + { + ReadDelimitedText( buf, line, 256 ); + tb.SetComment4( FROM_UTF8( buf ) ); + continue; + } + } + + return true; +} diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp new file mode 100644 index 00000000..0baaa1e5 --- /dev/null +++ b/eeschema/menubar.cpp @@ -0,0 +1,521 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2009-2014 Wayne Stambaugh + * 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 + */ + +/** + * @file eeschema/menubar.cpp + * @brief (Re)Create the main menubar for the schematic frame + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +void SCH_EDIT_FRAME::ReCreateMenuBar() +{ + // Create and try to get the current menubar + wxString text; + wxMenuBar* menuBar = GetMenuBar(); + + if( !menuBar ) + menuBar = new wxMenuBar(); + + // Delete all existing menus so they can be rebuilt. + // This allows language changes of the menu text on the fly. + menuBar->Freeze(); + + while( menuBar->GetMenuCount() ) + delete menuBar->Remove( 0 ); + + // Recreate all menus: + + // Menu File: + wxMenu* fileMenu = new wxMenu; + + if( Kiface().IsSingle() ) // not when under a project mgr + { + AddMenuItem( fileMenu, + ID_NEW_PROJECT, + _( "&New Schematic Project" ), + _( "Clear current schematic hierarchy and start a new schematic root sheet" ), + KiBitmap( new_sch_xpm ) ); + + text = AddHotkeyName( _( "&Open Schematic Project" ), g_Schematic_Hokeys_Descr, HK_LOAD_SCH ); + AddMenuItem( fileMenu, + ID_LOAD_PROJECT, text, + _( "Open an existing schematic hierarchy" ), + KiBitmap( open_document_xpm ) ); + } + + // @todo: static probably not OK in multiple open projects. + // Open Recent submenu + static wxMenu* openRecentMenu; + + // Add this menu to list menu managed by m_fileHistory + // (the file history will be updated when adding/removing files in history + if( openRecentMenu ) + Kiface().GetFileHistory().RemoveMenu( openRecentMenu ); + + openRecentMenu = new wxMenu(); + + Kiface().GetFileHistory().UseMenu( openRecentMenu ); + Kiface().GetFileHistory().AddFilesToMenu( openRecentMenu ); + + if( Kiface().IsSingle() ) // not when under a project mgr + { + AddMenuItem( fileMenu, openRecentMenu, + wxID_ANY, _( "Open &Recent" ), + _( "Open a recent opened schematic project" ), + KiBitmap( open_project_xpm ) ); + } + + AddMenuItem( fileMenu, + ID_APPEND_PROJECT, _( "App&end Schematic Sheet" ), + _( "Append schematic sheet to current project" ), + KiBitmap( open_document_xpm ) ); + + fileMenu->AppendSeparator(); + + text = AddHotkeyName( _( "&Save Schematic Project" ), + g_Schematic_Hokeys_Descr, HK_SAVE_SCH ); + AddMenuItem( fileMenu, + ID_SAVE_PROJECT, text, + _( "Save all sheets in schematic project" ), + KiBitmap( save_project_xpm ) ); + + AddMenuItem( fileMenu, + ID_UPDATE_ONE_SHEET, + _( "Save &Current Sheet Only" ), + _( "Save only current schematic sheet" ), + KiBitmap( save_xpm ) ); + + if( Kiface().IsSingle() ) // not when under a project mgr + { + AddMenuItem( fileMenu, + ID_SAVE_ONE_SHEET_UNDER_NEW_NAME, + _( "Save C&urrent Sheet As" ), + _( "Save current schematic sheet as..." ), + KiBitmap( save_as_xpm ) ); + } + + fileMenu->AppendSeparator(); + + AddMenuItem( fileMenu, + ID_SHEET_SET, + _( "Pa&ge Settings" ), + _( "Setting for sheet size and frame references" ), + KiBitmap( sheetset_xpm ) ); + + AddMenuItem( fileMenu, + wxID_PRINT, + _( "Pri&nt" ), + _( "Print schematic sheet" ), + KiBitmap( print_button_xpm ) ); + + // Plot submenu + wxMenu* choice_plot_fmt = new wxMenu; + AddMenuItem( choice_plot_fmt, ID_GEN_PLOT_SCHEMATIC, + _( "&Plot" ), + _( "Plot schematic sheet in PostScript, PDF, SVG, DXF or HPGL format" ), + KiBitmap( plot_xpm ) ); + + // Plot to Clipboard + AddMenuItem( choice_plot_fmt, ID_GEN_COPY_SHEET_TO_CLIPBOARD, + _( "Plot to C&lipboard" ), + _( "Export drawings to clipboard" ), + KiBitmap( copy_button_xpm ) ); + + // Plot + AddMenuItem( fileMenu, choice_plot_fmt, + ID_GEN_PLOT, _( "&Plot" ), + _( "Plot schematic sheet in HPGL, PostScript or SVG format" ), + KiBitmap( plot_xpm ) ); + + // Separator + fileMenu->AppendSeparator(); + + // Quit + AddMenuItem( fileMenu, + wxID_EXIT, + _( "&Close" ), + _( "Close Eeschema" ), + KiBitmap( exit_xpm ) ); + + // Menu Edit: + wxMenu* editMenu = new wxMenu; + + // Undo + text = AddHotkeyName( _( "&Undo" ), g_Schematic_Hokeys_Descr, HK_UNDO ); + + AddMenuItem( editMenu, wxID_UNDO, text, HELP_UNDO, KiBitmap( undo_xpm ) ); + + // Redo + text = AddHotkeyName( _( "&Redo" ), g_Schematic_Hokeys_Descr, HK_REDO ); + + AddMenuItem( editMenu, wxID_REDO, text, HELP_REDO, KiBitmap( redo_xpm ) ); + + // Delete + editMenu->AppendSeparator(); + AddMenuItem( editMenu, ID_SCHEMATIC_DELETE_ITEM_BUTT, + _( "&Delete" ), HELP_DELETE_ITEMS, + KiBitmap( delete_xpm ) ); + + // Find + editMenu->AppendSeparator(); + text = AddHotkeyName( _( "&Find" ), g_Schematic_Hokeys_Descr, HK_FIND_ITEM ); + AddMenuItem( editMenu, ID_FIND_ITEMS, text, HELP_FIND, KiBitmap( find_xpm ) ); + + // Find/Replace + text = AddHotkeyName( _( "Find and Re&place" ), g_Schematic_Hokeys_Descr, + HK_FIND_REPLACE ); + AddMenuItem( editMenu, wxID_REPLACE, text, HELP_REPLACE, + KiBitmap( find_replace_xpm ) ); + + // Import footprint association from the CvPcb cmp file: + editMenu->AppendSeparator(); + AddMenuItem( editMenu, ID_BACKANNO_ITEMS, + _( "Import Footprint Selection" ), + HELP_IMPORT_FOOTPRINTS, + KiBitmap( import_footprint_names_xpm ) ); + + // Menu View: + wxMenu* viewMenu = new wxMenu; + + /** + * Important Note for ZOOM IN and ZOOM OUT commands from menubar: + * we cannot add hotkey shortcut here, because the hotkey HK_ZOOM_IN and HK_ZOOM_OUT + * events(default = WXK_F1 and WXK_F2) are *NOT* equivalent to this menu command: + * zoom in and out from hotkeys are equivalent to the pop up menu zoom + * From here, zooming is made around the screen center + * From hotkeys, zooming is made around the mouse cursor position + * (obviously not possible from the toolbar or menubar command) + * + * in others words HK_ZOOM_IN and HK_ZOOM_OUT *are NOT* accelerators + * for Zoom in and Zoom out sub menus + * SO WE ADD THE NAME OF THE CORRESPONDING HOTKEY AS A COMMENT, NOT AS A SHORTCUT + * using in AddHotkeyName call the option "false" (not a shortcut) + */ + + text = AddHotkeyName( _( "Zoom &In" ), g_Schematic_Hokeys_Descr, + HK_ZOOM_IN, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( viewMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) ); + + text = AddHotkeyName( _( "Zoom &Out" ), g_Schematic_Hokeys_Descr, + HK_ZOOM_OUT, IS_ACCELERATOR ); // add accelerator, not a shortcut + AddMenuItem( viewMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) ); + + text = AddHotkeyName( _( "&Fit on Screen" ), g_Schematic_Hokeys_Descr, HK_ZOOM_AUTO ); + + AddMenuItem( viewMenu, ID_ZOOM_PAGE, text, HELP_ZOOM_FIT, KiBitmap( zoom_fit_in_page_xpm ) ); + + text = AddHotkeyName( _( "&Redraw" ), g_Schematic_Hokeys_Descr, HK_ZOOM_REDRAW ); + + AddMenuItem( viewMenu, ID_ZOOM_REDRAW, text, HELP_ZOOM_REDRAW, KiBitmap( zoom_redraw_xpm ) ); + + viewMenu->AppendSeparator(); + + AddMenuItem( viewMenu, + ID_HIERARCHY, + _( "Show &Hierarchical Navigator" ), + _( "Navigate hierarchical sheets" ), + KiBitmap( hierarchy_nav_xpm ) ); + + text = AddHotkeyName( _( "&Leave Sheet" ), g_Schematic_Hokeys_Descr, HK_LEAVE_SHEET ); + + AddMenuItem( viewMenu, + ID_POPUP_SCH_LEAVE_SHEET, + text, + _( "Leave Sheet" ), + KiBitmap( leave_sheet_xpm ) ); + + // Menu place: + wxMenu* placeMenu = new wxMenu; + + text = AddHotkeyName( _( "&Component" ), g_Schematic_Hokeys_Descr, + HK_ADD_NEW_COMPONENT, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_SCH_PLACE_COMPONENT, text, + HELP_PLACE_COMPONENTS, + KiBitmap( add_component_xpm ) ); + + text = AddHotkeyName( _( "&Power Port" ), g_Schematic_Hokeys_Descr, + HK_ADD_NEW_POWER, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_PLACE_POWER_BUTT, text, + HELP_PLACE_POWERPORT, + KiBitmap( add_power_xpm ) ); + + text = AddHotkeyName( _( "&Wire" ), g_Schematic_Hokeys_Descr, + HK_BEGIN_WIRE, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_WIRE_BUTT, text, + HELP_PLACE_WIRE, + KiBitmap( add_line_xpm ) ); + + text = AddHotkeyName( _( "&Bus" ), g_Schematic_Hokeys_Descr, + HK_BEGIN_BUS, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_BUS_BUTT, text, + HELP_PLACE_BUS, + KiBitmap( add_bus_xpm ) ); + + text = AddHotkeyName( _( "Wire to Bus &Entry" ), g_Schematic_Hokeys_Descr, + HK_ADD_WIRE_ENTRY, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_WIRETOBUS_ENTRY_BUTT, text, + HELP_PLACE_WIRE2BUS_ENTRY, + KiBitmap( add_line2bus_xpm ) ); + + text = AddHotkeyName( _( "Bus &to Bus Entry" ), g_Schematic_Hokeys_Descr, + HK_ADD_BUS_ENTRY, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_BUSTOBUS_ENTRY_BUTT, text, + HELP_PLACE_BUS2BUS_ENTRY, + KiBitmap( add_bus2bus_xpm ) ); + + text = AddHotkeyName( _( "&No Connect Flag" ), g_Schematic_Hokeys_Descr, + HK_ADD_NOCONN_FLAG, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_NOCONN_BUTT, text, HELP_PLACE_NC_FLAG, KiBitmap( noconn_xpm ) ); + + text = AddHotkeyName( _( "&Junction" ), g_Schematic_Hokeys_Descr, + HK_ADD_JUNCTION, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_JUNCTION_BUTT, text, + HELP_PLACE_JUNCTION, + KiBitmap( add_junction_xpm ) ); + + text = AddHotkeyName( _( "&Label" ), g_Schematic_Hokeys_Descr, + HK_ADD_LABEL, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_LABEL_BUTT, text, + HELP_PLACE_NETLABEL, + KiBitmap( add_line_label_xpm ) ); + + text = AddHotkeyName( _( "Gl&obal Label" ), g_Schematic_Hokeys_Descr, + HK_ADD_GLABEL, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_GLABEL_BUTT, text, + HELP_PLACE_GLOBALLABEL, + KiBitmap( add_glabel_xpm ) ); + + placeMenu->AppendSeparator(); + + text = AddHotkeyName( _( "&Hierarchical Label" ), g_Schematic_Hokeys_Descr, + HK_ADD_HLABEL, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_HIERLABEL_BUTT, + text, HELP_PLACE_HIER_LABEL, + KiBitmap( add_hierarchical_label_xpm ) ); + + + text = AddHotkeyName( _( "Hierarchical &Sheet" ), g_Schematic_Hokeys_Descr, + HK_ADD_HIER_SHEET, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_SHEET_SYMBOL_BUTT, text, + HELP_PLACE_SHEET, + KiBitmap( add_hierarchical_subsheet_xpm ) ); + + AddMenuItem( placeMenu, + ID_IMPORT_HLABEL_BUTT, + _( "I&mport Hierarchical Label" ), + HELP_IMPORT_SHEETPIN, + KiBitmap( import_hierarchical_label_xpm ) ); + + AddMenuItem( placeMenu, + ID_SHEET_PIN_BUTT, + _( "Hierarchical Pi&n to Sheet" ), + HELP_PLACE_SHEETPIN, + KiBitmap( add_hierar_pin_xpm ) ); + + placeMenu->AppendSeparator(); + + text = AddHotkeyName( _( "Graphic Pol&yline" ), g_Schematic_Hokeys_Descr, + HK_ADD_GRAPHIC_POLYLINE, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_LINE_COMMENT_BUTT, text, + HELP_PLACE_GRAPHICLINES, + KiBitmap( add_dashed_line_xpm ) ); + + text = AddHotkeyName( _( "&Graphic Text" ), g_Schematic_Hokeys_Descr, + HK_ADD_GRAPHIC_TEXT, IS_ACCELERATOR ); // add an accelerator, not a shortcut + AddMenuItem( placeMenu, ID_TEXT_COMMENT_BUTT, text, + HELP_PLACE_GRAPHICTEXTS, + KiBitmap( add_text_xpm ) ); + + // Graphic image + AddMenuItem( placeMenu, ID_ADD_IMAGE_BUTT, _( "&Image" ), + HELP_PLACE_GRAPHICIMAGES, + KiBitmap( image_xpm ) ); + + // Menu Preferences: + wxMenu* preferencesMenu = new wxMenu; + + // Library + AddMenuItem( preferencesMenu, + ID_CONFIG_REQ, + _( "Component &Libraries" ), + _( "Configure component libraries and paths" ), + KiBitmap( library_xpm ) ); + + // Colors + AddMenuItem( preferencesMenu, + ID_COLORS_SETUP, + _( "Set &Colors Scheme" ), + _( "Set color preferences" ), + KiBitmap( palette_xpm ) ); + + // Options (Preferences on WXMAC) + +#ifdef __WXMAC__ + preferencesMenu->Append( wxID_PREFERENCES ); +#else + AddMenuItem( preferencesMenu, + wxID_PREFERENCES, + _( "Schematic Editor &Options" ), + _( "Set Eeschema preferences" ), + KiBitmap( preference_xpm ) ); +#endif // __WXMAC__ + + + // Language submenu + Pgm().AddMenuLanguageList( preferencesMenu ); + + // Hotkey submenu + AddHotkeyConfigMenu( preferencesMenu ); + + // Separator + preferencesMenu->AppendSeparator(); + + AddMenuItem( preferencesMenu, + ID_CONFIG_SAVE, + _( "&Save Preferences" ), + _( "Save application preferences" ), + KiBitmap( save_setup_xpm ) ); + + AddMenuItem( preferencesMenu, + ID_CONFIG_READ, + _( "Load Prefe&rences" ), + _( "Load application preferences" ), + KiBitmap( read_setup_xpm ) ); + + // Menu Tools: + wxMenu* toolsMenu = new wxMenu; + + AddMenuItem( toolsMenu, + ID_RUN_LIBRARY, + _( "Library &Editor" ), HELP_RUN_LIB_EDITOR, + KiBitmap( libedit_xpm ) ); + + AddMenuItem( toolsMenu, + ID_TO_LIBVIEW, + _( "Library &Browser" ), HELP_RUN_LIB_VIEWER, + KiBitmap( library_browse_xpm ) ); + + AddMenuItem( toolsMenu, + ID_RESCUE_CACHED, + _( "&Rescue Old Components" ), + _( "Find old components in the project and rename/rescue them" ), + KiBitmap( copycomponent_xpm ) ); + + toolsMenu->AppendSeparator(); + + AddMenuItem( toolsMenu, + ID_GET_ANNOTATE, + _( "&Annotate Schematic" ), HELP_ANNOTATE, + KiBitmap( annotate_xpm ) ); + + // ERC + AddMenuItem( toolsMenu, + ID_GET_ERC, + _( "Electrical Rules &Checker" ), + _( "Perform electrical rules check" ), + KiBitmap( erc_xpm ) ); + + AddMenuItem( toolsMenu, + ID_GET_NETLIST, + _( "Generate &Netlist File" ), + _( "Generate the component netlist file" ), + KiBitmap( netlist_xpm ) ); + + AddMenuItem( toolsMenu, + ID_GET_TOOLS, + _( "Generate Bill of &Materials" ), + HELP_GENERATE_BOM, + KiBitmap( bom_xpm ) ); + + toolsMenu->AppendSeparator(); + + // Run CvPcb + AddMenuItem( toolsMenu, + ID_RUN_CVPCB, + _( "A&ssign Component Footprint" ), + _( "Run CvPcb" ), + KiBitmap( cvpcb_xpm ) ); + + // Run Pcbnew + AddMenuItem( toolsMenu, + ID_RUN_PCB, + _( "&Layout Printed Circuit Board" ), + _( "Run Pcbnew" ), + KiBitmap( pcbnew_xpm ) ); + + // Help Menu: + wxMenu* helpMenu = new wxMenu; + + // Version info + AddHelpVersionInfoMenuEntry( helpMenu ); + + AddMenuItem( helpMenu, + wxID_HELP, + _( "Eeschema &Manual" ), + _( "Open Eeschema Manual" ), + KiBitmap( online_help_xpm ) ); + + AddMenuItem( helpMenu, + wxID_INDEX, + _( "&Getting Started in KiCad" ), + _( "Open \"Getting Started in KiCad\" guide for beginners" ), + KiBitmap( help_xpm ) ); + + helpMenu->AppendSeparator(); + AddMenuItem( helpMenu, + wxID_ABOUT, + _( "&About KiCad" ), + _( "About KiCad" ), + KiBitmap( info_xpm ) ); + + // Create the menubar and append all submenus + menuBar->Append( fileMenu, _( "&File" ) ); + menuBar->Append( editMenu, _( "&Edit" ) ); + menuBar->Append( viewMenu, _( "&View" ) ); + menuBar->Append( placeMenu, _( "&Place" ) ); + menuBar->Append( preferencesMenu, _( "P&references" ) ); + menuBar->Append( toolsMenu, _( "&Tools" ) ); + menuBar->Append( helpMenu, _( "&Help" ) ); + + menuBar->Thaw(); + + // Associate the menu bar with the frame, if no previous menubar + if( GetMenuBar() == NULL ) + SetMenuBar( menuBar ); + else + menuBar->Refresh(); +} diff --git a/eeschema/menubar_libedit.cpp b/eeschema/menubar_libedit.cpp new file mode 100644 index 00000000..f2c95991 --- /dev/null +++ b/eeschema/menubar_libedit.cpp @@ -0,0 +1,297 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2009-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file eeschema/menubar_libedit.cpp + * @brief (Re)Create the main menubar for the component editor frame (LibEdit) + */ +#include +#include + +#include +#include +#include +#include + +#include +#include + +/** + * @brief (Re)Create the menubar for the component editor frame + */ +void LIB_EDIT_FRAME::ReCreateMenuBar() +{ + // Create and try to get the current menubar + wxString text; + wxMenuBar* menuBar = GetMenuBar(); + + if( !menuBar ) + menuBar = new wxMenuBar(); + + // Delete all existing menus so they can be rebuilt. + // This allows language changes of the menu text on the fly. + menuBar->Freeze(); + + while( menuBar->GetMenuCount() ) + delete menuBar->Remove( 0 ); + + // Recreate all menus: + + // Menu File: + wxMenu* fileMenu = new wxMenu; + + // Select current library + AddMenuItem( fileMenu, + ID_LIBEDIT_SELECT_CURRENT_LIB, + _( "&Current Library" ), + _( "Select working library" ), + KiBitmap( library_xpm ) ); + fileMenu->AppendSeparator(); + + // Save current library + AddMenuItem( fileMenu, + ID_LIBEDIT_SAVE_CURRENT_LIB, + _( "&Save Current Library\tCtrl+S" ), + _( "Save the current active library" ), + KiBitmap( save_xpm ) ); + + // Save current library as... + AddMenuItem( fileMenu, + ID_LIBEDIT_SAVE_CURRENT_LIB_AS, + _( "Save Current Library &As" ), + _( "Save current active library as..." ), + KiBitmap( save_as_xpm ) ); + + // Separator + fileMenu->AppendSeparator(); + + // Export as png file + AddMenuItem( fileMenu, + ID_LIBEDIT_GEN_PNG_FILE, + _( "Create &PNG File from Screen" ), + _( "Create a PNG file from the component displayed on screen" ), + KiBitmap( plot_xpm ) ); + + // Export as SVG file + AddMenuItem( fileMenu, + ID_LIBEDIT_GEN_SVG_FILE, + _( "Create S&VG File" ), + _( "Create a SVG file from the current loaded component" ), + KiBitmap( plot_svg_xpm ) ); + + // Separator + fileMenu->AppendSeparator(); + + // Quit + AddMenuItem( fileMenu, + wxID_EXIT, + _( "&Quit" ), + _( "Quit Library Editor" ), + KiBitmap( exit_xpm ) ); + + // Edit menu + wxMenu* editMenu = new wxMenu; + + // Undo + text = AddHotkeyName( _( "&Undo" ), g_Libedit_Hokeys_Descr, HK_UNDO ); + + AddMenuItem( editMenu, + wxID_UNDO, + text, + _( "Undo last edit" ), + KiBitmap( undo_xpm ) ); + + // Redo + text = AddHotkeyName( _( "&Redo" ), g_Libedit_Hokeys_Descr, HK_REDO ); + AddMenuItem( editMenu, + wxID_REDO, + text, + _( "Redo the last undo command" ), + KiBitmap( redo_xpm ) ); + + // Separator + editMenu->AppendSeparator(); + + // Delete + AddMenuItem( editMenu, + ID_LIBEDIT_DELETE_ITEM_BUTT, + _( "&Delete" ), + HELP_DELETE_ITEMS, + KiBitmap( delete_xpm ) ); + + // Menu View: + wxMenu* viewMenu = new wxMenu; + + /** + * Important Note for ZOOM IN and ZOOM OUT commands from menubar: + * we cannot add hotkey info here, because the hotkey HK_ZOOM_IN and HK_ZOOM_OUT + * events(default = WXK_F1 and WXK_F2) are *NOT* equivalent to this menu command: + * zoom in and out from hotkeys are equivalent to the pop up menu zoom + * From here, zooming is made around the screen center + * From hotkeys, zooming is made around the mouse cursor position + * (obviously not possible from the toolbar or menubar command) + * + * in others words HK_ZOOM_IN and HK_ZOOM_OUT *are NOT* accelerators + * for Zoom in and Zoom out sub menus + */ + + // Zoom in + text = _( "Zoom &In" ); + AddMenuItem( viewMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) ); + + // Zoom out + text = _( "Zoom &Out" ); + AddMenuItem( viewMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) ); + + // Fit on screen + text = AddHotkeyName( _( "&Fit on Screen" ), g_Libedit_Hokeys_Descr, HK_ZOOM_AUTO ); + AddMenuItem( viewMenu, ID_ZOOM_PAGE, text, HELP_ZOOM_FIT, KiBitmap( zoom_fit_in_page_xpm ) ); + + // Separator + viewMenu->AppendSeparator(); + + // Redraw + text = AddHotkeyName( _( "&Redraw" ), g_Libedit_Hokeys_Descr, HK_ZOOM_REDRAW ); + AddMenuItem( viewMenu, ID_ZOOM_REDRAW, text, HELP_ZOOM_REDRAW, KiBitmap( zoom_redraw_xpm ) ); + + // Menu Place: + wxMenu* placeMenu = new wxMenu; + + // Pin + AddMenuItem( placeMenu, + ID_LIBEDIT_PIN_BUTT, + _( "&Pin" ), + HELP_ADD_PIN, + KiBitmap( pin_xpm ) ); + + // Graphic text + AddMenuItem( placeMenu, + ID_LIBEDIT_BODY_TEXT_BUTT, + _( "Graphic &Text" ), + HELP_ADD_BODYTEXT, + KiBitmap( add_text_xpm ) ); + + // Graphic rectangle + AddMenuItem( placeMenu, + ID_LIBEDIT_BODY_RECT_BUTT, + _( "&Rectangle" ), + HELP_ADD_BODYRECT, + KiBitmap( add_rectangle_xpm ) ); + + // Graphic Circle + AddMenuItem( placeMenu, + ID_LIBEDIT_BODY_CIRCLE_BUTT, + _( "&Circle" ), + HELP_ADD_BODYCIRCLE, + KiBitmap( add_circle_xpm ) ); + + // Graphic Arc + AddMenuItem( placeMenu, + ID_LIBEDIT_BODY_ARC_BUTT, + _( "&Arc" ), + HELP_ADD_BODYARC, + KiBitmap( add_arc_xpm ) ); + + // Graphic Line or Polygon + AddMenuItem( placeMenu, + ID_LIBEDIT_BODY_LINE_BUTT, + _( "&Line or Polygon" ), + HELP_ADD_BODYPOLYGON, + KiBitmap( add_polygon_xpm ) ); + + // Menu Preferences: + wxMenu* preferencesMenu = new wxMenu; + + // Library list + AddMenuItem( preferencesMenu, + ID_CONFIG_REQ, + _( "Component &Libraries" ), + _( "Configure component libraries and paths" ), + KiBitmap( library_xpm ) ); + + // Default values and options + AddMenuItem( preferencesMenu, + wxID_PREFERENCES, + _( "Component Editor &Options" ), + _( "Set Component Editor default values and options" ), + KiBitmap( preference_xpm ) ); + + // Colors + AddMenuItem( preferencesMenu, + ID_COLORS_SETUP, + _( "Set &Colors Scheme" ), + _( "Set color preferences" ), + KiBitmap( palette_xpm ) ); + + // Language submenu + Pgm().AddMenuLanguageList( preferencesMenu ); + + // Hotkey submenu + AddHotkeyConfigMenu( preferencesMenu ); + + // Menu Help: + wxMenu* helpMenu = new wxMenu; + + // Version info + AddHelpVersionInfoMenuEntry( helpMenu ); + + // Contents + AddMenuItem( helpMenu, + wxID_HELP, + _( "Eeschema &Manual" ), + _( "Open the Eeschema Manual" ), + KiBitmap( online_help_xpm ) ); + + AddMenuItem( helpMenu, + wxID_INDEX, + _( "&Getting Started in KiCad" ), + _( "Open the \"Getting Started in KiCad\" guide for beginners" ), + KiBitmap( help_xpm ) ); + + // About Eeschema + helpMenu->AppendSeparator(); + + AddMenuItem( helpMenu, + wxID_ABOUT, + _( "&About KiCad" ), + _( "About KiCad" ), + KiBitmap( info_xpm ) ); + + // Create the menubar and append all submenus + menuBar->Append( fileMenu, _( "&File" ) ); + menuBar->Append( editMenu, _( "&Edit" ) ); + menuBar->Append( viewMenu, _( "&View" ) ); + menuBar->Append( placeMenu, _( "&Place" ) ); + menuBar->Append( preferencesMenu, _( "P&references" ) ); + menuBar->Append( helpMenu, _( "&Help" ) ); + + menuBar->Thaw(); + + // Associate the menu bar with the frame, if no previous menubar + if( GetMenuBar() == NULL ) + SetMenuBar( menuBar ); + else + menuBar->Refresh(); +} diff --git a/eeschema/netform.cpp b/eeschema/netform.cpp new file mode 100644 index 00000000..4939476c --- /dev/null +++ b/eeschema/netform.cpp @@ -0,0 +1,149 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2015 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema/netform.cpp + * @brief Net list generation code. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList, + int aFormat, const wxString& aFullFileName, + unsigned aNetlistOptions, REPORTER* aReporter ) +{ + bool res = true; + bool executeCommandLine = false; + + wxString fileName = aFullFileName; + + NETLIST_EXPORTER *helper; + + switch( aFormat ) + { + case NET_TYPE_PCBNEW: + helper = new NETLIST_EXPORTER_KICAD( aConnectedItemsList, Prj().SchLibs() ); + break; + + case NET_TYPE_ORCADPCB2: + helper = new NETLIST_EXPORTER_ORCADPCB2( aConnectedItemsList, Prj().SchLibs() ); + break; + + case NET_TYPE_CADSTAR: + helper = new NETLIST_EXPORTER_CADSTAR( aConnectedItemsList, Prj().SchLibs() ); + break; + + case NET_TYPE_SPICE: + helper = new NETLIST_EXPORTER_PSPICE( aConnectedItemsList, Prj().SchLibs() ); + break; + + default: + { + wxFileName tmpFile = fileName; + tmpFile.SetExt( GENERIC_INTERMEDIATE_NETLIST_EXT ); + fileName = tmpFile.GetFullPath(); + + helper = new NETLIST_EXPORTER_GENERIC( aConnectedItemsList, Prj().SchLibs() ); + executeCommandLine = true; + } + break; + } + + res = helper->WriteNetlist( fileName, aNetlistOptions ); + delete helper; + + // If user provided a plugin command line, execute it. + if( executeCommandLine && res && !m_netListerCommand.IsEmpty() ) + { + wxString prj_dir = Prj().GetProjectPath(); + + // build full command line from user's format string, e.g.: + // "xsltproc -o %O /usr/local/lib/kicad/plugins/netlist_form_pads-pcb.xsl %I" + // becomes, after the user selects /tmp/s1.net as the output file from the file dialog: + // "xsltproc -o /tmp/s1.net /usr/local/lib/kicad/plugins/netlist_form_pads-pcb.xsl /tmp/s1.xml" + wxString commandLine = NETLIST_EXPORTER::MakeCommandLine( m_netListerCommand, + fileName, aFullFileName, + prj_dir.SubString( 0, prj_dir.Len() - 2 ) // strip trailing '/' + ); + + if( aReporter ) + { + wxArrayString output, errors; + int diag = wxExecute( commandLine, output, errors, wxEXEC_SYNC ); + + wxString msg; + + msg << _( "Run command:" ) << wxT( "\n" ) << commandLine << wxT( "\n\n" ); + + aReporter->Report( msg, REPORTER::RPT_ACTION ); + + if( diag != 0 ) + aReporter->Report( wxString::Format( + _("Command error. Return code %d" ), diag ), + REPORTER::RPT_ERROR ); + else + aReporter->Report( _( "Success" ), REPORTER::RPT_INFO ); + + *aReporter << wxT("\n"); + + if( output.GetCount() ) + { + msg.Empty(); + msg << wxT( "\n" ) << _( "Info messages:" ) << wxT( "\n" ); + aReporter->Report( msg, REPORTER::RPT_INFO ); + + for( unsigned ii = 0; ii < output.GetCount(); ii++ ) + aReporter->Report( output[ii] + wxT( "\n" ), REPORTER::RPT_INFO ); + } + + if( errors.GetCount() ) + { + msg.Empty(); + msg << wxT("\n") << _( "Error messages:" ) << wxT( "\n" ); + aReporter->Report( msg, REPORTER::RPT_INFO ); + + for( unsigned ii = 0; ii < errors.GetCount(); ii++ ) + aReporter->Report( errors[ii] + wxT( "\n" ), REPORTER::RPT_ERROR ); + } + } + else + ProcessExecute( commandLine, wxEXEC_SYNC ); + } + + return res; +} diff --git a/eeschema/netlist.cpp b/eeschema/netlist.cpp new file mode 100644 index 00000000..10a1dddd --- /dev/null +++ b/eeschema/netlist.cpp @@ -0,0 +1,971 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file eeschema/netlist.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IS_WIRE false +#define IS_BUS true + +//Imported function: +int TestDuplicateSheetNames( bool aCreateMarker ); + + +bool SCH_EDIT_FRAME::prepareForNetlist() +{ + SCH_SHEET_LIST sheets; + + sheets.AnnotatePowerSymbols( Prj().SchLibs() ); + + // Performs some controls: + if( CheckAnnotate( NULL, 0 ) ) + { + // Schematic must be annotated: call Annotate dialog and tell + // the user why that is. + InvokeDialogAnnotate( this, _( "Exporting the netlist requires a " + "completely\nannotated schematic." ) ); + + if( CheckAnnotate( NULL, 0 ) ) + return false; + } + + // Test duplicate sheet names: + if( TestDuplicateSheetNames( false ) > 0 ) + { + if( !IsOK( NULL, _( "Error: duplicate sheet names. Continue?" ) ) ) + return false; + } + + // Cleanup the entire hierarchy + SCH_SCREENS screens; + + screens.SchematicCleanUp(); + + return true; +} + + +void SCH_EDIT_FRAME::sendNetlist() +{ + NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase(); + + NETLIST_EXPORTER_KICAD exporter( net_atoms, Prj().SchLibs() ); + + STRING_FORMATTER formatter; + + // @todo : trim GNL_ALL down to minimum for CVPCB + exporter.Format( &formatter, GNL_ALL ); + + Kiway().ExpressMail( FRAME_CVPCB, + MAIL_EESCHEMA_NETLIST, + formatter.GetString(), // an abbreviated "kicad" (s-expr) netlist + this + ); +} + + +bool SCH_EDIT_FRAME::CreateNetlist( int aFormat, const wxString& aFullFileName, + unsigned aNetlistOptions, REPORTER* aReporter ) +{ + if( !prepareForNetlist() ) + return false; + + std::auto_ptr connectedItemsList( BuildNetListBase() ); + + bool success = WriteNetListFile( connectedItemsList.release(), aFormat, + aFullFileName, aNetlistOptions, aReporter ); + + return success; +} + + +//#define NETLIST_DEBUG + +NETLIST_OBJECT_LIST::~NETLIST_OBJECT_LIST() +{ + Clear(); +} + + +void NETLIST_OBJECT_LIST::Clear() +{ + NETLIST_OBJECTS::iterator iter; + + for( iter = begin(); iter != end(); iter++ ) + { + NETLIST_OBJECT* item = *iter; + delete item; + } + + clear(); +} + + +void NETLIST_OBJECT_LIST::SortListbyNetcode() +{ + sort( this->begin(), this->end(), NETLIST_OBJECT_LIST::sortItemsbyNetcode ); +} + + +void NETLIST_OBJECT_LIST::SortListbySheet() +{ + sort( this->begin(), this->end(), NETLIST_OBJECT_LIST::sortItemsBySheet ); +} + + +NETLIST_OBJECT_LIST* SCH_EDIT_FRAME::BuildNetListBase() +{ + // I own this list until I return it to the new owner. + std::auto_ptr ret( new NETLIST_OBJECT_LIST() ); + + // Creates the flattened sheet list: + SCH_SHEET_LIST aSheets; + + // Build netlist info + bool success = ret->BuildNetListInfo( aSheets ); + + if( !success ) + { + SetStatusText( _( "No Objects" ) ); + return ret.release(); + } + + wxString msg = wxString::Format( _( "Net count = %d" ), int( ret->size() ) ); + + SetStatusText( msg ); + + return ret.release(); +} + + +bool NETLIST_OBJECT_LIST::BuildNetListInfo( SCH_SHEET_LIST& aSheets ) +{ + SCH_SHEET_PATH* sheet; + + // Fill list with connected items from the flattened sheet list + for( sheet = aSheets.GetFirst(); sheet != NULL; + sheet = aSheets.GetNext() ) + { + for( SCH_ITEM* item = sheet->LastScreen()->GetDrawItems(); item; item = item->Next() ) + { + item->GetNetListItem( *this, sheet ); + } + } + + if( size() == 0 ) + return false; + + // Sort objects by Sheet + SortListbySheet(); + + sheet = &(GetItem( 0 )->m_SheetPath); + m_lastNetCode = m_lastBusNetCode = 1; + + for( unsigned ii = 0, istart = 0; ii < size(); ii++ ) + { + NETLIST_OBJECT* net_item = GetItem( ii ); + + if( net_item->m_SheetPath != *sheet ) // Sheet change + { + sheet = &(net_item->m_SheetPath); + istart = ii; + } + + switch( net_item->m_Type ) + { + case NET_ITEM_UNSPECIFIED: + wxMessageBox( wxT( "BuildNetListInfo() error" ) ); + break; + + case NET_PIN: + case NET_PINLABEL: + case NET_SHEETLABEL: + case NET_NOCONNECT: + if( net_item->GetNet() != 0 ) + break; + + case NET_SEGMENT: + // Test connections point to point type without bus. + if( net_item->GetNet() == 0 ) + { + net_item->SetNet( m_lastNetCode ); + m_lastNetCode++; + } + + pointToPointConnect( net_item, IS_WIRE, istart ); + break; + + case NET_JUNCTION: + // Control of the junction outside BUS. + if( net_item->GetNet() == 0 ) + { + net_item->SetNet( m_lastNetCode ); + m_lastNetCode++; + } + + segmentToPointConnect( net_item, IS_WIRE, istart ); + + // Control of the junction, on BUS. + if( net_item->m_BusNetCode == 0 ) + { + net_item->m_BusNetCode = m_lastBusNetCode; + m_lastBusNetCode++; + } + + segmentToPointConnect( net_item, IS_BUS, istart ); + break; + + case NET_LABEL: + case NET_HIERLABEL: + case NET_GLOBLABEL: + // Test connections type junction without bus. + if( net_item->GetNet() == 0 ) + { + net_item->SetNet( m_lastNetCode ); + m_lastNetCode++; + } + + segmentToPointConnect( net_item, IS_WIRE, istart ); + break; + + case NET_SHEETBUSLABELMEMBER: + if( net_item->m_BusNetCode != 0 ) + break; + + case NET_BUS: + // Control type connections point to point mode bus + if( net_item->m_BusNetCode == 0 ) + { + net_item->m_BusNetCode = m_lastBusNetCode; + m_lastBusNetCode++; + } + + pointToPointConnect( net_item, IS_BUS, istart ); + break; + + case NET_BUSLABELMEMBER: + case NET_HIERBUSLABELMEMBER: + case NET_GLOBBUSLABELMEMBER: + // Control connections similar has on BUS + if( net_item->GetNet() == 0 ) + { + net_item->m_BusNetCode = m_lastBusNetCode; + m_lastBusNetCode++; + } + + segmentToPointConnect( net_item, IS_BUS, istart ); + break; + } + } + +#if defined(NETLIST_DEBUG) && defined(DEBUG) + std::cout << "\n\nafter sheet local\n\n"; + DumpNetTable(); +#endif + + // Updating the Bus Labels Netcode connected by Bus + connectBusLabels(); + + // Group objects by label. + for( unsigned ii = 0; ii < size(); ii++ ) + { + switch( GetItem( ii )->m_Type ) + { + case NET_PIN: + case NET_SHEETLABEL: + case NET_SEGMENT: + case NET_JUNCTION: + case NET_BUS: + case NET_NOCONNECT: + break; + + case NET_LABEL: + case NET_GLOBLABEL: + case NET_PINLABEL: + case NET_BUSLABELMEMBER: + case NET_GLOBBUSLABELMEMBER: + labelConnect( GetItem( ii ) ); + break; + + case NET_SHEETBUSLABELMEMBER: + case NET_HIERLABEL: + case NET_HIERBUSLABELMEMBER: + break; + + case NET_ITEM_UNSPECIFIED: + break; + } + } + +#if defined(NETLIST_DEBUG) && defined(DEBUG) + std::cout << "\n\nafter sheet global\n\n"; + DumpNetTable(); +#endif + + // Connection between hierarchy sheets + for( unsigned ii = 0; ii < size(); ii++ ) + { + if( GetItem( ii )->m_Type == NET_SHEETLABEL + || GetItem( ii )->m_Type == NET_SHEETBUSLABELMEMBER ) + sheetLabelConnect( GetItem( ii ) ); + } + + // Sort objects by NetCode + SortListbyNetcode(); + +#if defined(NETLIST_DEBUG) && defined(DEBUG) + std::cout << "\n\nafter qsort()\n"; + DumpNetTable(); +#endif + + // Compress numbers of Netcode having consecutive values. + int NetCode = 0; + m_lastNetCode = 0; + + for( unsigned ii = 0; ii < size(); ii++ ) + { + if( GetItem( ii )->GetNet() != m_lastNetCode ) + { + NetCode++; + m_lastNetCode = GetItem( ii )->GetNet(); + } + + GetItem( ii )->SetNet( NetCode ); + } + + // Set the minimal connection info: + setUnconnectedFlag(); + + // find the best label object to give the best net name to each net + findBestNetNameForEachNet(); + + return true; +} + +// Helper function to give a priority to sort labels: +// NET_PINLABEL, NET_GLOBBUSLABELMEMBER and NET_GLOBLABEL are global labels +// and the priority is high +static int getPriority( const NETLIST_OBJECT* Objet ) +{ + switch( Objet->m_Type ) + { + case NET_PIN: return 1; + case NET_LABEL: return 2; + case NET_HIERLABEL: return 3; + case NET_PINLABEL: return 4; + case NET_GLOBBUSLABELMEMBER: return 5; + case NET_GLOBLABEL: return 6; + default: break; + } + + return 0; +} + + +/* function evalLabelsPriority used by findBestNetNameForEachNet() + * evalLabelsPriority calculates the priority of alabel1 and aLabel2 + * return true if alabel1 has a higher priority than aLabel2 + */ +static bool evalLabelsPriority( const NETLIST_OBJECT* aLabel1, + const NETLIST_OBJECT* aLabel2 ) +{ + // Global labels have the highest prioriy. + // For local labels: names are prefixed by their sheetpath + // use name defined in the more top level hierarchical sheet + // (i.e. shorter timestamp path because paths are ///... + // and timestamp = 8 letters. + // Note: the final net name uses human sheetpath name, not timestamp sheetpath name + // They are equivalent, but not for human readers. + if( ! aLabel1->IsLabelGlobal() && ! aLabel2->IsLabelGlobal() ) + { + if( aLabel1->m_SheetPath.Path().Length() != aLabel2->m_SheetPath.Path().Length() ) + return aLabel1->m_SheetPath.Path().Length() < aLabel2->m_SheetPath.Path().Length(); + } + + int priority1 = getPriority( aLabel1 ); + int priority2 = getPriority( aLabel2 ); + + if( priority1 != priority2 ) + return priority1 > priority2; + + // Objects have here the same priority, therefore they have the same type. + // for global labels, we select the best candidate by alphabetic order + // because they have no sheetpath as prefix name + // for other labels, we select them before by sheet deep order + // because the actual name is /sheetpath/label + // and for a given path length, by alphabetic order + if( aLabel1->IsLabelGlobal() ) + return aLabel1->m_Label.Cmp( aLabel2->m_Label ) < 0; + + // Sheet paths have here the same length: use alphabetic label name order + // For labels on sheets having an equivalent deep in hierarchy, use + // alphabetic label name order: + if( aLabel1->m_Label.Cmp( aLabel2->m_Label ) != 0 ) + return aLabel1->m_Label.Cmp( aLabel2->m_Label ) < 0; + + // For identical labels having the same priority: choose the + // alphabetic label full name order + return aLabel1->m_SheetPath.PathHumanReadable().Cmp( + aLabel2->m_SheetPath.PathHumanReadable() ) < 0; +} + + +void NETLIST_OBJECT_LIST::findBestNetNameForEachNet() +{ + // Important note: NET_SHEETLABEL items of sheet items should *NOT* be considered, + // because they live in a sheet but their names are actually used in the subsheet. + // Moreover, in the parent sheet, the name of NET_SHEETLABEL can be not unique, + // ( for instance when 2 different sheets share the same schematic in complex hierarchies + // and 2 identical NET_SHEETLABEL labels can be connected to 2 different nets + + int netcode = 0; // current netcode for tested items + unsigned idxstart = 0; // index of the first item of this net + NETLIST_OBJECT* item; + NETLIST_OBJECT* candidate; + + // Pass 1: find the best name for labelled nets: + candidate = NULL; + for( unsigned ii = 0; ii <= size(); ii++ ) + { + if( ii == size() ) // last item already tested + item = NULL; + else + item = GetItem( ii ); + + if( !item || netcode != item->GetNet() ) // End of net found + { + if( candidate ) // One or more labels exists, find the best + { + for (unsigned jj = idxstart; jj < ii; jj++ ) + GetItem( jj )->SetNetNameCandidate( candidate ); + } + + if( item == NULL ) // End of list + break; + + // Prepare next net analysis: + netcode = item->GetNet(); + candidate = NULL; + idxstart = ii; + } + + switch( item->m_Type ) + { + case NET_HIERLABEL: + case NET_LABEL: + case NET_PINLABEL: + case NET_GLOBLABEL: + case NET_GLOBBUSLABELMEMBER: + // A candidate is found: select the better between the previous + // and this one + if( candidate == NULL ) + candidate = item; + else + { + if( evalLabelsPriority( item, candidate ) ) + // item has a highter priority than candidate + // so update the best candidate + candidate = item; + } + break; + + default: + break; + } + } + + // Pass 2: find the best name for not labelled nets: + // The "default" net name is Net-<_Pad> + // (see NETLIST_OBJECT::GetShortNetName()) + // therefore the "best" is the short net name alphabetically classed first + // (to avoid net names changes when the net is not modified, + // even if components are moved or deleted and undelete or replaced, as long + // the reference is kept) + + // Build a list of items with no net names + NETLIST_OBJECTS list; // no ownership of elements being pointed at + + for( unsigned ii = 0; ii < size(); ii++ ) + { + item = GetItem( ii ); + if( !item->HasNetNameCandidate() ) + list.push_back( item ); + } + + if( list.size() == 0 ) + return; + + idxstart = 0; + candidate = NULL; + netcode = list[0]->GetNet(); + + for( unsigned ii = 0; ii <= list.size(); ii++ ) + { + if( ii < list.size() ) + item = list[ii]; + else + item = NULL; + + if( !item || netcode != item->GetNet() ) // End of net found + { + if( candidate ) + { + for (unsigned jj = idxstart; jj < ii; jj++ ) + { + NETLIST_OBJECT* obj = list[jj]; + obj->SetNetNameCandidate( candidate ); + } + } + + if( !item ) + break; + + netcode = item->GetNet(); + candidate = NULL; + idxstart = ii; + } + + // Examine all pins of the net to find the best candidate, + // i.e. the first net name candidate, by alphabetic order + // the net names are built by GetShortNetName + // (Net-<{reference}-Pad{pad number}> like Net- + // Not named nets do not have usually a lot of members. + // Many have only 2 members(a pad and a non connection symbol) + if( item->m_Type == NET_PIN ) + { + // A candidate is found, however components which are not in + // netlist are not candidate because some have their reference + // changed each time the netlist is built (power components) + // and anyway obviously they are not a good candidate + SCH_COMPONENT* link = item->GetComponentParent(); + if( link && link->IsInNetlist() ) + { + // select the better between the previous and this one + item->SetNetNameCandidate( item ); // Needed to calculate GetShortNetName + + if( candidate == NULL ) + candidate = item; + else + { + if( item->GetShortNetName().Cmp( candidate->GetShortNetName() ) < 0 ) + candidate = item; + } + } + } + } +} + + +void NETLIST_OBJECT_LIST::sheetLabelConnect( NETLIST_OBJECT* SheetLabel ) +{ + if( SheetLabel->GetNet() == 0 ) + return; + + for( unsigned ii = 0; ii < size(); ii++ ) + { + NETLIST_OBJECT* ObjetNet = GetItem( ii ); + + if( ObjetNet->m_SheetPath != SheetLabel->m_SheetPathInclude ) + continue; //use SheetInclude, not the sheet!! + + if( (ObjetNet->m_Type != NET_HIERLABEL ) && (ObjetNet->m_Type != NET_HIERBUSLABELMEMBER ) ) + continue; + + if( ObjetNet->GetNet() == SheetLabel->GetNet() ) + continue; //already connected. + + if( ObjetNet->m_Label.CmpNoCase( SheetLabel->m_Label ) != 0 ) + continue; //different names. + + // Propagate Netcode having all the objects of the same Netcode. + if( ObjetNet->GetNet() ) + propageNetCode( ObjetNet->GetNet(), SheetLabel->GetNet(), IS_WIRE ); + else + ObjetNet->SetNet( SheetLabel->GetNet() ); + } +} + + +void NETLIST_OBJECT_LIST::connectBusLabels() +{ + // Propagate the net code between all bus label member objects connected by they name. + // If the net code is not yet existing, a new one is created + // Search is done in the entire list + for( unsigned ii = 0; ii < size(); ii++ ) + { + NETLIST_OBJECT* Label = GetItem( ii ); + + if( Label->IsLabelBusMemberType() ) + { + if( Label->GetNet() == 0 ) + { + // Not yet existiing net code: create a new one. + Label->SetNet( m_lastNetCode ); + m_lastNetCode++; + } + + for( unsigned jj = ii + 1; jj < size(); jj++ ) + { + NETLIST_OBJECT* LabelInTst = GetItem( jj ); + + if( LabelInTst->IsLabelBusMemberType() ) + { + if( LabelInTst->m_BusNetCode != Label->m_BusNetCode ) + continue; + + if( LabelInTst->m_Member != Label->m_Member ) + continue; + + if( LabelInTst->GetNet() == 0 ) + // Append this object to the current net + LabelInTst->SetNet( Label->GetNet() ); + else + // Merge the 2 net codes, they are connected. + propageNetCode( LabelInTst->GetNet(), Label->GetNet(), IS_WIRE ); + } + } + } + } +} + + +void NETLIST_OBJECT_LIST::propageNetCode( int aOldNetCode, int aNewNetCode, bool aIsBus ) +{ + if( aOldNetCode == aNewNetCode ) + return; + + if( aIsBus == false ) // Propagate NetCode + { + for( unsigned jj = 0; jj < size(); jj++ ) + { + NETLIST_OBJECT* object = GetItem( jj ); + + if( object->GetNet() == aOldNetCode ) + object->SetNet( aNewNetCode ); + } + } + else // Propagate BusNetCode + { + for( unsigned jj = 0; jj < size(); jj++ ) + { + NETLIST_OBJECT* object = GetItem( jj ); + + if( object->m_BusNetCode == aOldNetCode ) + object->m_BusNetCode = aNewNetCode; + } + } +} + + +void NETLIST_OBJECT_LIST::pointToPointConnect( NETLIST_OBJECT* aRef, bool aIsBus, + int start ) +{ + int netCode; + + if( aIsBus == false ) // Objects other than BUS and BUSLABELS + { + netCode = aRef->GetNet(); + + for( unsigned i = start; i < size(); i++ ) + { + NETLIST_OBJECT* item = GetItem( i ); + + if( item->m_SheetPath != aRef->m_SheetPath ) //used to be > (why?) + continue; + + switch( item->m_Type ) + { + case NET_SEGMENT: + case NET_PIN: + case NET_LABEL: + case NET_HIERLABEL: + case NET_GLOBLABEL: + case NET_SHEETLABEL: + case NET_PINLABEL: + case NET_JUNCTION: + case NET_NOCONNECT: + if( aRef->m_Start == item->m_Start + || aRef->m_Start == item->m_End + || aRef->m_End == item->m_Start + || aRef->m_End == item->m_End ) + { + if( item->GetNet() == 0 ) + item->SetNet( netCode ); + else + propageNetCode( item->GetNet(), netCode, IS_WIRE ); + } + break; + + case NET_BUS: + case NET_BUSLABELMEMBER: + case NET_SHEETBUSLABELMEMBER: + case NET_HIERBUSLABELMEMBER: + case NET_GLOBBUSLABELMEMBER: + case NET_ITEM_UNSPECIFIED: + break; + } + } + } + else // Object type BUS, BUSLABELS, and junctions. + { + netCode = aRef->m_BusNetCode; + + for( unsigned i = start; i < size(); i++ ) + { + NETLIST_OBJECT* item = GetItem( i ); + + if( item->m_SheetPath != aRef->m_SheetPath ) + continue; + + switch( item->m_Type ) + { + case NET_ITEM_UNSPECIFIED: + case NET_SEGMENT: + case NET_PIN: + case NET_LABEL: + case NET_HIERLABEL: + case NET_GLOBLABEL: + case NET_SHEETLABEL: + case NET_PINLABEL: + case NET_NOCONNECT: + break; + + case NET_BUS: + case NET_BUSLABELMEMBER: + case NET_SHEETBUSLABELMEMBER: + case NET_HIERBUSLABELMEMBER: + case NET_GLOBBUSLABELMEMBER: + case NET_JUNCTION: + if( aRef->m_Start == item->m_Start + || aRef->m_Start == item->m_End + || aRef->m_End == item->m_Start + || aRef->m_End == item->m_End ) + { + if( item->m_BusNetCode == 0 ) + item->m_BusNetCode = netCode; + else + propageNetCode( item->m_BusNetCode, netCode, IS_BUS ); + } + break; + } + } + } +} + + +void NETLIST_OBJECT_LIST::segmentToPointConnect( NETLIST_OBJECT* aJonction, + bool aIsBus, int aIdxStart ) +{ + for( unsigned i = aIdxStart; i < size(); i++ ) + { + NETLIST_OBJECT* segment = GetItem( i ); + + // if different sheets, obviously no physical connection between elements. + if( segment->m_SheetPath != aJonction->m_SheetPath ) + continue; + + if( aIsBus == IS_WIRE ) + { + if( segment->m_Type != NET_SEGMENT ) + continue; + } + else + { + if( segment->m_Type != NET_BUS ) + continue; + } + + if( IsPointOnSegment( segment->m_Start, segment->m_End, aJonction->m_Start ) ) + { + // Propagation Netcode has all the objects of the same Netcode. + if( aIsBus == IS_WIRE ) + { + if( segment->GetNet() ) + propageNetCode( segment->GetNet(), aJonction->GetNet(), aIsBus ); + else + segment->SetNet( aJonction->GetNet() ); + } + else + { + if( segment->m_BusNetCode ) + propageNetCode( segment->m_BusNetCode, aJonction->m_BusNetCode, aIsBus ); + else + segment->m_BusNetCode = aJonction->m_BusNetCode; + } + } + } +} + + +void NETLIST_OBJECT_LIST::labelConnect( NETLIST_OBJECT* aLabelRef ) +{ + if( aLabelRef->GetNet() == 0 ) + return; + + for( unsigned i = 0; i < size(); i++ ) + { + NETLIST_OBJECT* item = GetItem( i ); + + if( item->GetNet() == aLabelRef->GetNet() ) + continue; + + if( item->m_SheetPath != aLabelRef->m_SheetPath ) + { + if( item->m_Type != NET_PINLABEL && item->m_Type != NET_GLOBLABEL + && item->m_Type != NET_GLOBBUSLABELMEMBER ) + continue; + + if( (item->m_Type == NET_GLOBLABEL + || item->m_Type == NET_GLOBBUSLABELMEMBER) + && item->m_Type != aLabelRef->m_Type ) + //global labels only connect other global labels. + continue; + } + + // NET_HIERLABEL are used to connect sheets. + // NET_LABEL are local to a sheet + // NET_GLOBLABEL are global. + // NET_PINLABEL is a kind of global label (generated by a power pin invisible) + if( item->IsLabelType() ) + { + if( item->m_Label.CmpNoCase( aLabelRef->m_Label ) != 0 ) + continue; + + if( item->GetNet() ) + propageNetCode( item->GetNet(), aLabelRef->GetNet(), IS_WIRE ); + else + item->SetNet( aLabelRef->GetNet() ); + } + } +} + + +void NETLIST_OBJECT_LIST::setUnconnectedFlag() +{ + NETLIST_OBJECT* NetItemRef; + unsigned NetStart, NetEnd; + NET_CONNECTION_T StateFlag; + + NetStart = NetEnd = 0; + StateFlag = UNCONNECTED; + for( unsigned ii = 0; ii < size(); ii++ ) + { + NetItemRef = GetItem( ii ); + if( NetItemRef->m_Type == NET_NOCONNECT && StateFlag != PAD_CONNECT ) + StateFlag = NOCONNECT_SYMBOL_PRESENT; + + // Analysis of current net. + unsigned idxtoTest = ii + 1; + + if( ( idxtoTest >= size() ) + || ( NetItemRef->GetNet() != GetItem( idxtoTest )->GetNet() ) ) + { + // Net analysis to update m_ConnectionType + NetEnd = idxtoTest; + + /* set m_ConnectionType member to StateFlag for all items of + * this net: */ + for( unsigned kk = NetStart; kk < NetEnd; kk++ ) + GetItem( kk )->m_ConnectionType = StateFlag; + + if( idxtoTest >= size() ) + return; + + // Start Analysis next Net + StateFlag = UNCONNECTED; + NetStart = idxtoTest; + continue; + } + + /* test the current item: if this is a pin and if the reference item + * is also a pin, then 2 pins are connected, so set StateFlag to + * PAD_CONNECT (can be already done) Of course, if the current + * item is a no connect symbol, set StateFlag to + * NOCONNECT_SYMBOL_PRESENT to inhibit error diags. However if + * StateFlag is already set to PAD_CONNECT this state is kept (the + * no connect symbol was surely an error and an ERC will report this) + */ + for( ; ; idxtoTest++ ) + { + if( ( idxtoTest >= size() ) + || ( NetItemRef->GetNet() != GetItem( idxtoTest )->GetNet() ) ) + break; + + switch( GetItem( idxtoTest )->m_Type ) + { + case NET_ITEM_UNSPECIFIED: + wxMessageBox( wxT( "BuildNetListBase() error" ) ); + break; + + case NET_SEGMENT: + case NET_LABEL: + case NET_HIERLABEL: + case NET_GLOBLABEL: + case NET_SHEETLABEL: + case NET_PINLABEL: + case NET_BUS: + case NET_BUSLABELMEMBER: + case NET_SHEETBUSLABELMEMBER: + case NET_HIERBUSLABELMEMBER: + case NET_GLOBBUSLABELMEMBER: + case NET_JUNCTION: + break; + + case NET_PIN: + if( NetItemRef->m_Type == NET_PIN ) + StateFlag = PAD_CONNECT; + + break; + + case NET_NOCONNECT: + if( StateFlag != PAD_CONNECT ) + StateFlag = NOCONNECT_SYMBOL_PRESENT; + + break; + } + } + } +} diff --git a/eeschema/netlist.h b/eeschema/netlist.h new file mode 100644 index 00000000..2d20554a --- /dev/null +++ b/eeschema/netlist.h @@ -0,0 +1,62 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2011 jean-pierre Charras + * Copyright (C) 1992-2011 Wayne Stambaugh + * Copyright (C) 1992-2015 KiCad Developers, see changelog.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 + */ + + +/** + * @file netlist.h + */ + +#ifndef _NETLIST_H_ +#define _NETLIST_H_ + +/// netlist types +enum NETLIST_TYPE_ID { + NET_TYPE_UNINIT = 0, + NET_TYPE_PCBNEW, + NET_TYPE_ORCADPCB2, + NET_TYPE_CADSTAR, + NET_TYPE_SPICE, + NET_TYPE_CUSTOM1, /* NET_TYPE_CUSTOM1 + * is the first id for user netlist format + * NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1 + * is the last id for user netlist format + */ + //NET_TYPE_CUSTOM_MAX = NET_TYPE_CUSTOM1 + CUSTOMPANEL_COUNTMAX - 1 +}; + + +/// Options for Spice netlist generation (OR'ed bits +enum netlistOptions { + NET_USE_X_PREFIX = 2, // for Spice netlist : change "U" and "IC" reference prefix to "X" + NET_USE_NETCODES_AS_NETNAMES = 4 // for Spice netlist : use netcode numbers as netnames +}; + + +#define NETLIST_HEAD_STRING "EESchema Netlist Version 1.1" + +// Max pin number per component and footprint +#define MAXPIN 5000 + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter.cpp b/eeschema/netlist_exporters/netlist_exporter.cpp new file mode 100644 index 00000000..62e39ccc --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter.cpp @@ -0,0 +1,364 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 + */ + + +/** + * @file netlist_exporter.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +wxString NETLIST_EXPORTER::MakeCommandLine( const wxString& aFormatString, + const wxString& aTempfile, const wxString& aFinalFile, const wxString& aProjectPath ) +{ + // Expand format symbols in the command line: + // %B => base filename of selected output file, minus path and extension. + // %P => project directory name, without trailing '/' or '\'. + // %I => full filename of the input file (the intermediate net file). + // %O => complete filename and path (but without extension) of the user chosen output file. + + wxString ret = aFormatString; + wxFileName in = aTempfile; + wxFileName out = aFinalFile; + + ret.Replace( wxT( "%P" ), aProjectPath.GetData(), true ); + ret.Replace( wxT( "%B" ), out.GetName().GetData(), true ); + ret.Replace( wxT( "%I" ), in.GetFullPath().GetData(), true ); + ret.Replace( wxT( "%O" ), out.GetFullPath().GetData(), true ); + + // Use Unix like notation, which always works + ret.Replace( wxT( "\\" ), "/", true ); + + return ret; +} + + +void NETLIST_EXPORTER::sprintPinNetName( wxString& aResult, + const wxString& aNetNameFormat, NETLIST_OBJECT* aPin, + bool aUseNetcodeAsNetName ) +{ + int netcode = aPin->GetNet(); + + // Not wxString::Clear(), which would free memory. We want the worst + // case wxString memory to grow to avoid reallocation from within the + // caller's loop. + aResult.Empty(); + + if( netcode != 0 && aPin->GetConnectionType() == PAD_CONNECT ) + { + if( aUseNetcodeAsNetName ) + { + aResult.Printf( wxT("%d"), netcode ); + } + else + { + aResult = aPin->GetNetName(); + + if( aResult.IsEmpty() ) // No net name: give a name from net code + aResult.Printf( aNetNameFormat.GetData(), netcode ); + } + } +} + + +SCH_COMPONENT* NETLIST_EXPORTER::findNextComponent( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath ) +{ + wxString ref; + + // continue searching from the middle of a linked list (the draw list) + for( ; aItem; aItem = aItem->Next() ) + { + if( aItem->Type() != SCH_COMPONENT_T ) + continue; + + // found next component + SCH_COMPONENT* comp = (SCH_COMPONENT*) aItem; + + // Power symbols and other components which have the reference starting + // with "#" are not included in netlist (pseudo or virtual components) + ref = comp->GetRef( aSheetPath ); + if( ref[0] == wxChar( '#' ) ) + continue; + + // if( Component->m_FlagControlMulti == 1 ) + // continue; /* yes */ + // removed because with multiple instances of one schematic + // (several sheets pointing to 1 screen), this will be erroneously be + // toggled. + + LIB_PART* part = m_libs->FindLibPart( comp->GetPartName() ); + if( !part ) + continue; + + // If component is a "multi parts per package" type + if( part->GetUnitCount() > 1 ) + { + // test if this reference has already been processed, and if so skip + if( m_ReferencesAlreadyFound.Lookup( ref ) ) + continue; + } + + // record the usage of this library component entry. + m_LibParts.insert( part ); // rejects non-unique pointers + + return comp; + } + + return NULL; +} + + +/// Comparison routine for sorting by pin numbers. +static bool sortPinsByNum( NETLIST_OBJECT* aPin1, NETLIST_OBJECT* aPin2 ) +{ + // return "lhs < rhs" + return RefDesStringCompare( aPin1->GetPinNumText(), aPin2->GetPinNumText() ) < 0; +} + + +SCH_COMPONENT* NETLIST_EXPORTER::findNextComponentAndCreatePinList( EDA_ITEM* aItem, + SCH_SHEET_PATH* aSheetPath ) +{ + wxString ref; + + m_SortedComponentPinList.clear(); + + // continue searching from the middle of a linked list (the draw list) + for( ; aItem; aItem = aItem->Next() ) + { + if( aItem->Type() != SCH_COMPONENT_T ) + continue; + + // found next component + SCH_COMPONENT* comp = (SCH_COMPONENT*) aItem; + + // Power symbols and other components which have the reference starting + // with "#" are not included in netlist (pseudo or virtual components) + ref = comp->GetRef( aSheetPath ); + + if( ref[0] == wxChar( '#' ) ) + continue; + + // if( Component->m_FlagControlMulti == 1 ) + // continue; /* yes */ + // removed because with multiple instances of one schematic + // (several sheets pointing to 1 screen), this will be erroneously be + // toggled. + + LIB_PART* part = m_libs->FindLibPart( comp->GetPartName() ); + + if( !part ) + continue; + + // If component is a "multi parts per package" type + if( part->GetUnitCount() > 1 ) + { + // test if this reference has already been processed, and if so skip + if( m_ReferencesAlreadyFound.Lookup( ref ) ) + continue; + + // Collect all pins for this reference designator by searching + // the entire design for other parts with the same reference designator. + // This is only done once, it would be too expensive otherwise. + findAllInstancesOfComponent( comp, part, aSheetPath ); + } + + else // entry->GetUnitCount() <= 1 means one part per package + { + LIB_PINS pins; // constructed once here + + part->GetPins( pins, comp->GetUnitSelection( aSheetPath ), comp->GetConvert() ); + + for( size_t i = 0; i < pins.size(); i++ ) + { + LIB_PIN* pin = pins[i]; + + wxASSERT( pin->Type() == LIB_PIN_T ); + + addPinToComponentPinList( comp, aSheetPath, pin ); + } + } + + // Sort pins in m_SortedComponentPinList by pin number + sort( m_SortedComponentPinList.begin(), + m_SortedComponentPinList.end(), sortPinsByNum ); + + // Remove duplicate Pins in m_SortedComponentPinList + eraseDuplicatePins( ); + + // record the usage of this library component entry. + m_LibParts.insert( part ); // rejects non-unique pointers + + return comp; + } + + return NULL; +} + +bool NETLIST_EXPORTER::addPinToComponentPinList( SCH_COMPONENT* aComponent, + SCH_SHEET_PATH* aSheetPath, LIB_PIN* aPin ) +{ + // Search the PIN description for Pin in g_NetObjectslist + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + { + NETLIST_OBJECT* pin = m_masterList->GetItem( ii ); + + if( pin->m_Type != NET_PIN ) + continue; + + if( pin->m_Link != aComponent ) + continue; + + if( pin->m_PinNum != aPin->GetNumber() ) + continue; + + // most expensive test at the end. + if( pin->m_SheetPath != *aSheetPath ) + continue; + + m_SortedComponentPinList.push_back( pin ); + + if( m_SortedComponentPinList.size() >= MAXPIN ) + { + // Log message for Internal error + DisplayError( NULL, wxT( "addPinToComponentPinList err: MAXPIN reached" ) ); + } + + return true; // we're done, we appended. + } + + return false; +} + + +void NETLIST_EXPORTER::eraseDuplicatePins() +{ + for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) + { + if( m_SortedComponentPinList[ii] == NULL ) /* already deleted */ + continue; + + /* Search for duplicated pins + * If found, remove duplicates. The priority is to keep connected pins + * and remove unconnected + * - So this allows (for instance when using multi op amps per package + * - to connect only one op amp to power + * Because the pin list is sorted by m_PinNum value, duplicated pins + * are necessary successive in list + */ + int idxref = ii; + for( unsigned jj = ii + 1; jj < m_SortedComponentPinList.size(); jj++ ) + { + if( m_SortedComponentPinList[jj] == NULL ) // Already removed + continue; + + // if other pin num, stop search, + // because all pins having the same number are consecutive in list. + if( m_SortedComponentPinList[idxref]->m_PinNum != m_SortedComponentPinList[jj]->m_PinNum ) + break; + + if( m_SortedComponentPinList[idxref]->GetConnectionType() == PAD_CONNECT ) + { + m_SortedComponentPinList[jj]->m_Flag = 1; + m_SortedComponentPinList[jj] = NULL; + } + else /* the reference pin is not connected: remove this pin if the + * other pin is connected */ + { + if( m_SortedComponentPinList[jj]->GetConnectionType() == PAD_CONNECT ) + { + m_SortedComponentPinList[idxref]->m_Flag = 1; + m_SortedComponentPinList[idxref] = NULL; + idxref = jj; + } + else // the 2 pins are not connected: remove the tested pin, + { // and continue ... + m_SortedComponentPinList[jj]->m_Flag = 1; + m_SortedComponentPinList[jj] = NULL; + } + } + } + } +} + + +void NETLIST_EXPORTER::findAllInstancesOfComponent( SCH_COMPONENT* aComponent, + LIB_PART* aEntry, + SCH_SHEET_PATH* aSheetPath ) +{ + wxString ref = aComponent->GetRef( aSheetPath ); + wxString ref2; + + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* sheet = sheetList.GetFirst(); sheet; sheet = sheetList.GetNext() ) + { + for( EDA_ITEM* item = sheet->LastDrawList(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + SCH_COMPONENT* comp2 = (SCH_COMPONENT*) item; + + ref2 = comp2->GetRef( sheet ); + if( ref2.CmpNoCase( ref ) != 0 ) + continue; + + int unit2 = comp2->GetUnitSelection( sheet ); // slow + + for( LIB_PIN* pin = aEntry->GetNextPin(); pin; pin = aEntry->GetNextPin( pin ) ) + { + wxASSERT( pin->Type() == LIB_PIN_T ); + + if( pin->GetUnit() && pin->GetUnit() != unit2 ) + continue; + + if( pin->GetConvert() && pin->GetConvert() != comp2->GetConvert() ) + continue; + + // A suitable pin is found: add it to the current list + addPinToComponentPinList( comp2, sheet, pin ); + } + } + } +} + diff --git a/eeschema/netlist_exporters/netlist_exporter.h b/eeschema/netlist_exporters/netlist_exporter.h new file mode 100644 index 00000000..dc3ebb0c --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter.h @@ -0,0 +1,235 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORTER_H +#define NETLIST_EXPORTER_H + +#include + +#include +#include +#include +#include +#include +#include + +/** + * Class UNIQUE_STRINGS + * tracks unique wxStrings and is useful in telling if a string + * has been seen before. + */ +class UNIQUE_STRINGS +{ + std::set m_set; ///< set of wxStrings already found + + typedef std::set::iterator us_iterator; + +public: + /** + * Function Clear + * erases the record. + */ + void Clear() { m_set.clear(); } + + /** + * Function Lookup + * returns true if \a aString already exists in the set, otherwise returns + * false and adds \a aString to the set for next time. + */ + bool Lookup( const wxString& aString ) + { + std::pair pair = m_set.insert( aString ); + + return !pair.second; + } +}; + +/** + * Struct LIB_PART_LESS_THAN + * is used by std:set instantiation which uses LIB_PART name as its key. + */ +struct LIB_PART_LESS_THAN +{ + // a "less than" test on two LIB_PARTs (.m_name wxStrings) + bool operator()( LIB_PART* const& libpart1, LIB_PART* const& libpart2 ) const + { + // Use case specific GetName() wxString compare + return libpart1->GetName().Cmp( libpart2->GetName() ) < 0; + } +}; + +/** + * Class NETLIST_EXPORTER + * is a abstract class used for the netlist exporters that eeschema supports. + */ +class NETLIST_EXPORTER +{ +protected: + NETLIST_OBJECT_LIST* m_masterList; /// yes ownership, connected items flat list + + PART_LIBS* m_libs; /// no ownership + + /// Used to temporary store and filter the list of pins of a schematic component + /// when generating schematic component data in netlist (comp section). No ownership + /// of members. + NETLIST_OBJECTS m_SortedComponentPinList; + + /// Used for "multi parts per package" components, + /// avoids processing a lib component more than once. + UNIQUE_STRINGS m_ReferencesAlreadyFound; + + /// unique library parts used. LIB_PART items are sorted by names + std::set m_LibParts; + + // share a code generated std::set to reduce code volume + std::set m_Libraries; ///< unique libraries used + + /** + * Function sprintPinNetName + * formats the net name for \a aPin using \a aNetNameFormat into \a aResult. + *

      + * Net name is: + *

        + *
      • "?" if pin not connected + *
      • "netname" for global net (like gnd, vcc .. + *
      • "/path/netname" for the usual nets + *
      + * if aUseNetcodeAsNetName is true, the net name is just the net code (SPICE only) + */ + static void sprintPinNetName( wxString& aResult, const wxString& aNetNameFormat, + NETLIST_OBJECT* aPin, bool aUseNetcodeAsNetName = false ); + + /** + * Function findNextComponentAndCreatePinList + * finds a component from the DrawList and builds + * its pin list in m_SortedComponentPinList. This list is sorted by pin num. + * the component is the next actual component after aItem + * (power symbols and virtual components that have their reference starting by '#'are skipped). + */ + SCH_COMPONENT* findNextComponentAndCreatePinList( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath ); + + SCH_COMPONENT* findNextComponent( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath ); + + + /** + * Function eraseDuplicatePins + * erase duplicate Pins from m_SortedComponentPinList (i.e. set pointer in this list to NULL). + * (This is a list of pins found in the whole schematic, for a single + * component.) These duplicate pins were put in list because some pins (powers... ) + * are found more than one time when we have a multiple parts per package + * component. For instance, a 74ls00 has 4 parts, and therefore the VCC pin + * and GND pin appears 4 times in the list. + * Note: this list *MUST* be sorted by pin number (.m_PinNum member value) + * Also set the m_Flag member of "removed" NETLIST_OBJECT pin item to 1 + */ + void eraseDuplicatePins(); + + /** + * Function addPinToComponentPinList + * adds a new pin description to the pin list m_SortedComponentPinList. + * A pin description is a pointer to the corresponding structure + * created by BuildNetList() in the table g_NetObjectslist. + */ + bool addPinToComponentPinList( SCH_COMPONENT* Component, + SCH_SHEET_PATH* sheet, + LIB_PIN* PinEntry ); + + /** + * Function findAllInstancesOfComponent + * is used for "multiple parts per package" components. + *

      + * Search the entire design for all instances of \a aComponent based on + * matching reference designator, and for each part, add all its pins + * to the temporary sorted pin list. + */ + void findAllInstancesOfComponent( SCH_COMPONENT* aComponent, + LIB_PART* aEntry, + SCH_SHEET_PATH* aSheetPath ); + +public: + + /** + * Constructor + * @param aMasterList we take ownership of this here. + */ + NETLIST_EXPORTER( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + m_masterList( aMasterList ), + m_libs( aLibs ) + { + } + + virtual ~NETLIST_EXPORTER() + { + delete m_masterList; // I own the list itself in this instance. + } + + /** + * Function WriteNetlist + * writes to specified output file + */ + virtual bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) + { + return false; + } + + /** + * Function MakeCommandLine + * builds up a string that describes a command line for + * executing a child process. The input and output file names + * along with any options to the executable are all possibly + * in the returned string. + * + * @param aFormatString holds: + *

        + *
      • the name of the external program + *
      • any options needed by that program + *
      • formatting sequences, see below. + *
      + * + * @param aTempfile is the name of an input file to the + * external program. + * @param aFinalFile is the name of an output file that + * the user expects. + * @param aProjectDirectory is used for %P replacement, it should omit + * the trailing '/'. + * + *

      Supported formatting sequences and their meaning: + *

        + *
      • %B => base filename of selected output file, minus + * path and extension. + *
      • %I => complete filename and path of the temporary + * input file. + *
      • %O => complete filename and path of the user chosen + * output file. + *
      • %P => project directory, without name and without trailing '/' + *
      + */ + static wxString MakeCommandLine( const wxString& aFormatString, + const wxString& aTempfile, const wxString& aFinalFile, + const wxString& aProjectDirectory + ); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp b/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp new file mode 100644 index 00000000..2b5b7fbf --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_cadstar.cpp @@ -0,0 +1,204 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 +#include +#include + +#include +#include +#include + +#include "netlist_exporter_cadstar.h" + +/* Generate CADSTAR net list. */ +static wxString StartLine( wxT( "." ) ); + +bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) +{ + (void)aNetlistOptions; //unused + int ret = 0; + FILE* f = NULL; + + if( ( f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == NULL ) + { + wxString msg; + msg.Printf( _( "Failed to create file '%s'" ), + GetChars( aOutFileName ) ); + DisplayError( NULL, msg ); + return false; + } + + wxString StartCmpDesc = StartLine + wxT( "ADD_COM" ); + wxString msg; + SCH_SHEET_PATH* sheet; + EDA_ITEM* DrawList; + SCH_COMPONENT* component; + wxString title = wxT( "Eeschema " ) + GetBuildVersion(); + + ret |= fprintf( f, "%sHEA\n", TO_UTF8( StartLine ) ); + ret |= fprintf( f, "%sTIM %s\n", TO_UTF8( StartLine ), TO_UTF8( DateAndTime() ) ); + ret |= fprintf( f, "%sAPP ", TO_UTF8( StartLine ) ); + ret |= fprintf( f, "\"%s\"\n", TO_UTF8( title ) ); + ret |= fprintf( f, "\n" ); + + // Prepare list of nets generation + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + // Create netlist module section + m_ReferencesAlreadyFound.Clear(); + + SCH_SHEET_LIST SheetList; + + for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) + { + for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Next() ) + { + DrawList = component = findNextComponentAndCreatePinList( DrawList, sheet ); + + if( component == NULL ) + break; + + /* + doing nothing with footprint + if( !component->GetField( FOOTPRINT )->IsVoid() ) + { + footprint = component->GetField( FOOTPRINT )->m_Text; + footprint.Replace( wxT( " " ), wxT( "_" ) ); + } + else + footprint = wxT( "$noname" ); + */ + + msg = component->GetRef( sheet ); + ret |= fprintf( f, "%s ", TO_UTF8( StartCmpDesc ) ); + ret |= fprintf( f, "%s", TO_UTF8( msg ) ); + + msg = component->GetField( VALUE )->GetText(); + msg.Replace( wxT( " " ), wxT( "_" ) ); + ret |= fprintf( f, " \"%s\"", TO_UTF8( msg ) ); + ret |= fprintf( f, "\n" ); + } + } + + ret |= fprintf( f, "\n" ); + + m_SortedComponentPinList.clear(); + + if( ! writeListOfNets( f ) ) + ret = -1; // set error + + ret |= fprintf( f, "\n%sEND\n", TO_UTF8( StartLine ) ); + + fclose( f ); + + return ret >= 0; +} + + +bool NETLIST_EXPORTER_CADSTAR::writeListOfNets( FILE* f ) +{ + int ret = 0; + wxString InitNetDesc = StartLine + wxT( "ADD_TER" ); + wxString StartNetDesc = StartLine + wxT( "TER" ); + wxString netcodeName, InitNetDescLine; + unsigned ii; + int print_ter = 0; + int NetCode, lastNetCode = -1; + SCH_COMPONENT* Cmp; + wxString netName; + + for( ii = 0; ii < m_masterList->size(); ii++ ) + { + NETLIST_OBJECT* nitem = m_masterList->GetItem( ii ); + + // Get the NetName of the current net : + if( ( NetCode = nitem->GetNet() ) != lastNetCode ) + { + netName = nitem->GetNetName(); + netcodeName = wxT( "\"" ); + + if( !netName.IsEmpty() ) + netcodeName << netName; + else // this net has no name: create a default name $ + netcodeName << wxT( "$" ) << NetCode; + + netcodeName += wxT( "\"" ); + lastNetCode = NetCode; + print_ter = 0; + } + + + if( nitem->m_Type != NET_PIN ) + continue; + + if( nitem->m_Flag != 0 ) + continue; + + Cmp = nitem->GetComponentParent(); + wxString refstr = Cmp->GetRef( &nitem->m_SheetPath ); + if( refstr[0] == '#' ) + continue; // Power supply symbols. + + switch( print_ter ) + { + case 0: + { + char buf[5]; + wxString str_pinnum; + strncpy( buf, (char*) &nitem->m_PinNum, 4 ); + buf[4] = 0; + str_pinnum = FROM_UTF8( buf ); + InitNetDescLine.Printf( wxT( "\n%s %s %.4s %s" ), + GetChars( InitNetDesc ), + GetChars( refstr ), + GetChars( str_pinnum ), + GetChars( netcodeName ) ); + } + print_ter++; + break; + + case 1: + ret |= fprintf( f, "%s\n", TO_UTF8( InitNetDescLine ) ); + ret |= fprintf( f, "%s %s %.4s\n", + TO_UTF8( StartNetDesc ), + TO_UTF8( refstr ), + (char*) &nitem->m_PinNum ); + print_ter++; + break; + + default: + ret |= fprintf( f, " %s %.4s\n", + TO_UTF8( refstr ), + (char*) &nitem->m_PinNum ); + break; + } + + nitem->m_Flag = 1; + } + + return ret >= 0; +} diff --git a/eeschema/netlist_exporters/netlist_exporter_cadstar.h b/eeschema/netlist_exporters/netlist_exporter_cadstar.h new file mode 100644 index 00000000..909e1bdb --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_cadstar.h @@ -0,0 +1,62 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORTER_CADSTAR_H +#define NETLIST_EXPORTER_CADSTAR_H + +#include "netlist_exporter.h" + +/** + * Class NETLIST_EXPORTER_CADSTAR + * generates a netlist compatible with CADSTAR + */ +class NETLIST_EXPORTER_CADSTAR : public NETLIST_EXPORTER +{ + /** + * Function writeListOfNetsCADSTAR + * writes a net list (ranked by Netcode), and pins connected to it. + *

      + * Format: + * - ADD_TER RR2 6 \"$42\" + * - B U1 100 + * - 6 CA + *

      + */ + bool writeListOfNets( FILE* f ); + +public: + NETLIST_EXPORTER_CADSTAR( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + NETLIST_EXPORTER( aMasterList, aLibs ) + { + } + + /** + * Function WriteList + * writes to specified output file + */ + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter_generic.cpp b/eeschema/netlist_exporters/netlist_exporter_generic.cpp new file mode 100644 index 00000000..921e0fc1 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_generic.cpp @@ -0,0 +1,580 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 +#include +#include + +#include +#include "netlist_exporter_generic.h" + +static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 ); + +bool NETLIST_EXPORTER_GENERIC::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) +{ + // Prepare list of nets generation + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + // output the XML format netlist. + wxXmlDocument xdoc; + + xdoc.SetRoot( makeRoot( GNL_ALL ) ); + + return xdoc.Save( aOutFileName, 2 /* indent bug, today was ignored by wxXml lib */ ); +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeRoot( int aCtl ) +{ + XNODE* xroot = node( wxT( "export" ) ); + + xroot->AddAttribute( wxT( "version" ), wxT( "D" ) ); + + if( aCtl & GNL_HEADER ) + // add the "design" header + xroot->AddChild( makeDesignHeader() ); + + if( aCtl & GNL_COMPONENTS ) + xroot->AddChild( makeComponents() ); + + if( aCtl & GNL_PARTS ) + xroot->AddChild( makeLibParts() ); + + if( aCtl & GNL_LIBRARIES ) + // must follow makeGenericLibParts() + xroot->AddChild( makeLibraries() ); + + if( aCtl & GNL_NETS ) + xroot->AddChild( makeListOfNets() ); + + return xroot; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeComponents() +{ + XNODE* xcomps = node( wxT( "components" ) ); + + wxString timeStamp; + + // some strings we need many times, but don't want to construct more + // than once for performance. These are used within loops so the + // enclosing wxString constructor would fire on each loop iteration if + // they were in a nested scope. + + // these are actually constructor invocations, not assignments as it appears: + wxString sFields = wxT( "fields" ); + wxString sField = wxT( "field" ); + wxString sComponent = wxT( "comp" ); // use "part" ? + wxString sName = wxT( "name" ); + wxString sRef = wxT( "ref" ); + wxString sPins = wxT( "pins" ); + wxString sPin = wxT( "pin" ); + wxString sValue = wxT( "value" ); + wxString sSheetPath = wxT( "sheetpath" ); + wxString sFootprint = wxT( "footprint" ); + wxString sDatasheet = wxT( "datasheet" ); + wxString sTStamp = wxT( "tstamp" ); + wxString sTStamps = wxT( "tstamps" ); + wxString sTSFmt = wxT( "%8.8lX" ); // comp->m_TimeStamp + wxString sLibSource = wxT( "libsource" ); + wxString sLibPart = wxT( "libpart" ); + wxString sLib = wxT( "lib" ); + wxString sPart = wxT( "part" ); + wxString sNames = wxT( "names" ); + + m_ReferencesAlreadyFound.Clear(); + + SCH_SHEET_LIST sheetList; + + // Output is xml, so there is no reason to remove spaces from the field values. + // And XML element names need not be translated to various languages. + + for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext() ) + { + for( EDA_ITEM* schItem = path->LastDrawList(); schItem; schItem = schItem->Next() ) + { + SCH_COMPONENT* comp = findNextComponentAndCreatePinList( schItem, path ); + if( !comp ) + break; // No component left + + schItem = comp; + + XNODE* xcomp; // current component being constructed + + // Output the component's elements in order of expected access frequency. + // This may not always look best, but it will allow faster execution + // under XSL processing systems which do sequential searching within + // an element. + + xcomps->AddChild( xcomp = node( sComponent ) ); + xcomp->AddAttribute( sRef, comp->GetRef( path ) ); + + xcomp->AddChild( node( sValue, comp->GetField( VALUE )->GetText() ) ); + + if( !comp->GetField( FOOTPRINT )->IsVoid() ) + xcomp->AddChild( node( sFootprint, comp->GetField( FOOTPRINT )->GetText() ) ); + + if( !comp->GetField( DATASHEET )->IsVoid() ) + xcomp->AddChild( node( sDatasheet, comp->GetField( DATASHEET )->GetText() ) ); + + // Export all user defined fields within the component, + // which start at field index MANDATORY_FIELDS. Only output the + // container element if there are any s. + if( comp->GetFieldCount() > MANDATORY_FIELDS ) + { + XNODE* xfields; + xcomp->AddChild( xfields = node( sFields ) ); + + for( int fldNdx = MANDATORY_FIELDS; fldNdx < comp->GetFieldCount(); ++fldNdx ) + { + SCH_FIELD* f = comp->GetField( fldNdx ); + + // only output a field if non empty and not just "~" + if( !f->IsVoid() ) + { + XNODE* xfield; + xfields->AddChild( xfield = node( sField, f->GetText() ) ); + xfield->AddAttribute( sName, f->GetName() ); + } + } + } + + XNODE* xlibsource; + xcomp->AddChild( xlibsource = node( sLibSource ) ); + + // "logical" library name, which is in anticipation of a better search + // algorithm for parts based on "logical_lib.part" and where logical_lib + // is merely the library name minus path and extension. + LIB_PART* part = m_libs->FindLibPart( comp->GetPartName() ); + if( part ) + xlibsource->AddAttribute( sLib, part->GetLib()->GetLogicalName() ); + + xlibsource->AddAttribute( sPart, comp->GetPartName() ); + + XNODE* xsheetpath; + + xcomp->AddChild( xsheetpath = node( sSheetPath ) ); + xsheetpath->AddAttribute( sNames, path->PathHumanReadable() ); + xsheetpath->AddAttribute( sTStamps, path->Path() ); + + timeStamp.Printf( sTSFmt, (unsigned long)comp->GetTimeStamp() ); + xcomp->AddChild( node( sTStamp, timeStamp ) ); + } + } + + return xcomps; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeDesignHeader() +{ + SCH_SCREEN* screen; + XNODE* xdesign = node( wxT("design") ); + XNODE* xtitleBlock; + XNODE* xsheet; + XNODE* xcomment; + wxString sheetTxt; + wxFileName sourceFileName; + + // the root sheet is a special sheet, call it source + xdesign->AddChild( node( wxT( "source" ), g_RootSheet->GetScreen()->GetFileName() ) ); + + xdesign->AddChild( node( wxT( "date" ), DateAndTime() ) ); + + // which Eeschema tool + xdesign->AddChild( node( wxT( "tool" ), wxT( "Eeschema " ) + GetBuildVersion() ) ); + + /* + Export the sheets information + */ + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* sheet = sheetList.GetFirst(); sheet; sheet = sheetList.GetNext() ) + { + screen = sheet->LastScreen(); + + xdesign->AddChild( xsheet = node( wxT( "sheet" ) ) ); + + // get the string representation of the sheet index number. + // Note that sheet->GetIndex() is zero index base and we need to increment the number by one to make + // human readable + sheetTxt.Printf( wxT( "%d" ), ( sheetList.GetIndex() + 1 ) ); + xsheet->AddAttribute( wxT( "number" ), sheetTxt ); + xsheet->AddAttribute( wxT( "name" ), sheet->PathHumanReadable() ); + xsheet->AddAttribute( wxT( "tstamps" ), sheet->Path() ); + + + TITLE_BLOCK tb = screen->GetTitleBlock(); + + xsheet->AddChild( xtitleBlock = node( wxT( "title_block" ) ) ); + + xtitleBlock->AddChild( node( wxT( "title" ), tb.GetTitle() ) ); + xtitleBlock->AddChild( node( wxT( "company" ), tb.GetCompany() ) ); + xtitleBlock->AddChild( node( wxT( "rev" ), tb.GetRevision() ) ); + xtitleBlock->AddChild( node( wxT( "date" ), tb.GetDate() ) ); + + // We are going to remove the fileName directories. + sourceFileName = wxFileName( screen->GetFileName() ); + xtitleBlock->AddChild( node( wxT( "source" ), sourceFileName.GetFullName() ) ); + + xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) ); + xcomment->AddAttribute( wxT("number"), wxT("1") ); + xcomment->AddAttribute( wxT( "value" ), tb.GetComment1() ); + + xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) ); + xcomment->AddAttribute( wxT("number"), wxT("2") ); + xcomment->AddAttribute( wxT( "value" ), tb.GetComment2() ); + + xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) ); + xcomment->AddAttribute( wxT("number"), wxT("3") ); + xcomment->AddAttribute( wxT( "value" ), tb.GetComment3() ); + + xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) ); + xcomment->AddAttribute( wxT("number"), wxT("4") ); + xcomment->AddAttribute( wxT( "value" ), tb.GetComment4() ); + } + + return xdesign; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeLibraries() +{ + XNODE* xlibs = node( wxT( "libraries" ) ); // auto_ptr + + for( std::set::iterator it = m_Libraries.begin(); it!=m_Libraries.end(); ++it ) + { + PART_LIB* lib = (PART_LIB*) *it; + XNODE* xlibrary; + + xlibs->AddChild( xlibrary = node( wxT( "library" ) ) ); + xlibrary->AddAttribute( wxT( "logical" ), lib->GetLogicalName() ); + xlibrary->AddChild( node( wxT( "uri" ), lib->GetFullFileName() ) ); + + // @todo: add more fun stuff here + } + + return xlibs; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeLibParts() +{ + XNODE* xlibparts = node( wxT( "libparts" ) ); // auto_ptr + wxString sLibpart = wxT( "libpart" ); + wxString sLib = wxT( "lib" ); + wxString sPart = wxT( "part" ); + wxString sAliases = wxT( "aliases" ); + wxString sAlias = wxT( "alias" ); + wxString sPins = wxT( "pins" ); // key for library component pins list + wxString sPin = wxT( "pin" ); // key for one library component pin descr + wxString sPinNum = wxT( "num" ); // key for one library component pin num + wxString sPinName = wxT( "name" ); // key for one library component pin name + wxString sPinType = wxT( "type" ); // key for one library component pin electrical type + wxString sName = wxT( "name" ); + wxString sField = wxT( "field" ); + wxString sFields = wxT( "fields" ); + wxString sDescr = wxT( "description" ); + wxString sDocs = wxT( "docs" ); + wxString sFprints = wxT( "footprints" ); + wxString sFp = wxT( "fp" ); + + LIB_PINS pinList; + LIB_FIELDS fieldList; + + m_Libraries.clear(); + + for( std::set::iterator it = m_LibParts.begin(); it!=m_LibParts.end(); ++it ) + { + LIB_PART* lcomp = *it; + PART_LIB* library = lcomp->GetLib(); + + m_Libraries.insert( library ); // inserts component's library if unique + + XNODE* xlibpart; + xlibparts->AddChild( xlibpart = node( sLibpart ) ); + xlibpart->AddAttribute( sLib, library->GetLogicalName() ); + xlibpart->AddAttribute( sPart, lcomp->GetName() ); + + if( lcomp->GetAliasCount() ) + { + wxArrayString aliases = lcomp->GetAliasNames( false ); + if( aliases.GetCount() ) + { + XNODE* xaliases = node( sAliases ); + xlibpart->AddChild( xaliases ); + for( unsigned i=0; iAddChild( node( sAlias, aliases[i] ) ); + } + } + } + + //----- show the important properties ------------------------- + if( !lcomp->GetAlias( 0 )->GetDescription().IsEmpty() ) + xlibpart->AddChild( node( sDescr, lcomp->GetAlias( 0 )->GetDescription() ) ); + + if( !lcomp->GetAlias( 0 )->GetDocFileName().IsEmpty() ) + xlibpart->AddChild( node( sDocs, lcomp->GetAlias( 0 )->GetDocFileName() ) ); + + // Write the footprint list + if( lcomp->GetFootPrints().GetCount() ) + { + XNODE* xfootprints; + xlibpart->AddChild( xfootprints = node( sFprints ) ); + + for( unsigned i=0; iGetFootPrints().GetCount(); ++i ) + { + xfootprints->AddChild( node( sFp, lcomp->GetFootPrints()[i] ) ); + } + } + + //----- show the fields here ---------------------------------- + fieldList.clear(); + lcomp->GetFields( fieldList ); + + XNODE* xfields; + xlibpart->AddChild( xfields = node( sFields ) ); + + for( unsigned i=0; iAddChild( xfield = node( sField, fieldList[i].GetText() ) ); + xfield->AddAttribute( sName, fieldList[i].GetName(false) ); + } + } + + //----- show the pins here ------------------------------------ + pinList.clear(); + lcomp->GetPins( pinList, 0, 0 ); + + /* we must erase redundant Pins references in pinList + * These redundant pins exist because some pins + * are found more than one time when a component has + * multiple parts per package or has 2 representations (DeMorgan conversion) + * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes, + * and therefore each pin appears 2 times in the list. + * Common pins (VCC, GND) can also be found more than once. + */ + sort( pinList.begin(), pinList.end(), sortPinsByNumber ); + for( int ii = 0; ii < (int)pinList.size()-1; ii++ ) + { + if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() ) + { // 2 pins have the same number, remove the redundant pin at index i+1 + pinList.erase(pinList.begin() + ii + 1); + ii--; + } + } + + if( pinList.size() ) + { + XNODE* pins; + + xlibpart->AddChild( pins = node( sPins ) ); + for( unsigned i=0; iAddChild( pin = node( sPin ) ); + pin->AddAttribute( sPinNum, pinList[i]->GetNumberString() ); + pin->AddAttribute( sPinName, pinList[i]->GetName() ); + pin->AddAttribute( sPinType, pinList[i]->GetCanonicalElectricalTypeName() ); + + // caution: construction work site here, drive slowly + } + } + } + + return xlibparts; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets() +{ + XNODE* xnets = node( wxT( "nets" ) ); // auto_ptr if exceptions ever get used. + wxString netCodeTxt; + wxString netName; + wxString ref; + + wxString sNet = wxT( "net" ); + wxString sName = wxT( "name" ); + wxString sCode = wxT( "code" ); + wxString sRef = wxT( "ref" ); + wxString sPin = wxT( "pin" ); + wxString sNode = wxT( "node" ); + wxString sFmtd = wxT( "%d" ); + + XNODE* xnet = 0; + int netCode; + int lastNetCode = -1; + int sameNetcodeCount = 0; + + + /* output: + + + + + */ + + m_LibParts.clear(); // must call this function before using m_LibParts. + + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + { + NETLIST_OBJECT* nitem = m_masterList->GetItem( ii ); + SCH_COMPONENT* comp; + + // New net found, write net id; + if( ( netCode = nitem->GetNet() ) != lastNetCode ) + { + sameNetcodeCount = 0; // item count for this net + netName = nitem->GetNetName(); + lastNetCode = netCode; + } + + if( nitem->m_Type != NET_PIN ) + continue; + + if( nitem->m_Flag != 0 ) // Redundant pin, skip it + continue; + + comp = nitem->GetComponentParent(); + + // Get the reference for the net name and the main parent component + ref = comp->GetRef( &nitem->m_SheetPath ); + if( ref[0] == wxChar( '#' ) ) + continue; + + if( ++sameNetcodeCount == 1 ) + { + xnets->AddChild( xnet = node( sNet ) ); + netCodeTxt.Printf( sFmtd, netCode ); + xnet->AddAttribute( sCode, netCodeTxt ); + xnet->AddAttribute( sName, netName ); + } + + XNODE* xnode; + xnet->AddChild( xnode = node( sNode ) ); + xnode->AddAttribute( sRef, ref ); + xnode->AddAttribute( sPin, nitem->GetPinNumText() ); + } + + return xnets; +} + + +bool NETLIST_EXPORTER_GENERIC::writeListOfNets( FILE* f, NETLIST_OBJECT_LIST& aObjectsList ) +{ + int ret = 0; + int netCode; + int lastNetCode = -1; + int sameNetcodeCount = 0; + wxString netName; + wxString ref; + wxString netcodeName; + char firstItemInNet[256]; + + for( unsigned ii = 0; ii < aObjectsList.size(); ii++ ) + { + SCH_COMPONENT* comp; + NETLIST_OBJECT* nitem = aObjectsList[ii]; + + // New net found, write net id; + if( ( netCode = nitem->GetNet() ) != lastNetCode ) + { + sameNetcodeCount = 0; // Items count for this net + netName = nitem->GetNetName(); + + netcodeName.Printf( wxT( "Net %d " ), netCode ); + netcodeName << wxT( "\"" ) << netName << wxT( "\"" ); + + // Add the netname without prefix, in cases we need only the + // "short" netname + netcodeName += wxT( " \"" ) + nitem->GetShortNetName() + wxT( "\"" ); + lastNetCode = netCode; + } + + if( nitem->m_Type != NET_PIN ) + continue; + + if( nitem->m_Flag != 0 ) // Redundant pin, skip it + continue; + + comp = nitem->GetComponentParent(); + + // Get the reference for the net name and the main parent component + ref = comp->GetRef( &nitem->m_SheetPath ); + if( ref[0] == wxChar( '#' ) ) + continue; // Pseudo component (Like Power symbol) + + // Print the pin list for this net, use special handling if + // 2 or more items are connected: + + // if first item for this net found, defer printing this connection + // until a second item will is found + if( ++sameNetcodeCount == 1 ) + { + snprintf( firstItemInNet, sizeof(firstItemInNet), " %s %.4s\n", + TO_UTF8( ref ), + (const char*) &aObjectsList[ii]->m_PinNum ); + } + + // Second item for this net found, print the Net name, and the + // first item + if( sameNetcodeCount == 2 ) + { + ret |= fprintf( f, "%s\n", TO_UTF8( netcodeName ) ); + ret |= fputs( firstItemInNet, f ); + } + + if( sameNetcodeCount >= 2 ) + ret |= fprintf( f, " %s %.4s\n", TO_UTF8( ref ), + (const char*) &nitem->m_PinNum ); + } + + return ret >= 0; +} + + +XNODE* NETLIST_EXPORTER_GENERIC::node( const wxString& aName, const wxString& aTextualContent /* = wxEmptyString*/ ) +{ + XNODE* n = new XNODE( wxXML_ELEMENT_NODE, aName ); + + if( aTextualContent.Len() > 0 ) // excludes wxEmptyString, the parameter's default value + n->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, aTextualContent ) ); + + return n; +} + + +static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 ) +{ + // return "lhs < rhs" + return RefDesStringCompare( aPin1->GetNumberString(), aPin2->GetNumberString() ) < 0; +} diff --git a/eeschema/netlist_exporters/netlist_exporter_generic.h b/eeschema/netlist_exporters/netlist_exporter_generic.h new file mode 100644 index 00000000..89d57d57 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_generic.h @@ -0,0 +1,135 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORT_GENERIC_H +#define NETLIST_EXPORT_GENERIC_H + +#include + +#include // also nests: + +#define GENERIC_INTERMEDIATE_NETLIST_EXT wxT( "xml" ) + +/** + * Enum GNL + * is a set of bit which control the totality of the tree built by makeRoot() + */ +enum GNL_T +{ + GNL_LIBRARIES = 1 << 0, + GNL_COMPONENTS = 1 << 1, + GNL_PARTS = 1 << 2, + GNL_HEADER = 1 << 3, + GNL_NETS = 1 << 4, +}; + + +/** + * Class NETLIST_EXPORTER_GENERIC + * generates a generic XML based netlist file. This allows using XSLT or other methods to + * transform the XML to other netlist formats outside of the C++ codebase. + */ +class NETLIST_EXPORTER_GENERIC : public NETLIST_EXPORTER +{ +public: + NETLIST_EXPORTER_GENERIC( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + NETLIST_EXPORTER( aMasterList, aLibs ) + { + } + + /** + * Function WriteNetlist + * writes to specified output file + */ + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); + +#define GNL_ALL ( GNL_LIBRARIES | GNL_COMPONENTS | GNL_PARTS | GNL_HEADER | GNL_NETS ) + +protected: + /** + * Function node + * is a convenience function that creates a new XNODE with an optional textual child. + * It also provides some insulation from a possible change in XML library. + * + * @param aName is the name to associate with a new node of type wxXML_ELEMENT_NODE. + * @param aTextualContent is optional, and if given is the text to include in a child + * of the returned node, and has type wxXML_TEXT_NODE. + */ + XNODE* node( const wxString& aName, const wxString& aTextualContent = wxEmptyString ); + + /** + * Function writeGENERICListOfNets + * writes out nets (ranked by Netcode), and elements that are + * connected as part of that net. + */ + bool writeListOfNets( FILE* f, NETLIST_OBJECT_LIST& aObjectsList ); + + /** + * Function makeGenericRoot + * builds the entire document tree for the generic export. This is factored + * out here so we can write the tree in either S-expression file format + * or in XML if we put the tree built here into a wxXmlDocument. + * @param aCtl - a bitset or-ed together from GNL_ENUM values + * @return XNODE* - the root nodes + */ + XNODE* makeRoot( int aCtl = GNL_ALL ); + + /** + * Function makeComponents + * @return XNODE* - returns a sub-tree holding all the schematic components. + */ + XNODE* makeComponents(); + + /** + * Function makeDesignHeader + * fills out a project "design" header into an XML node. + * @return XNODE* - the design header + */ + XNODE* makeDesignHeader(); + + /** + * Function makeLibParts + * fills out an XML node with the unique library parts and returns it. + * @return XNODE* - the library parts nodes + */ + XNODE* makeLibParts(); + + /** + * Function makeListOfNets + * fills out an XML node with a list of nets and returns it. + * @return XNODE* - the list of nets nodes + */ + XNODE* makeListOfNets(); + + /** + * Function makeLibraries + * fills out an XML node with a list of used libraries and returns it. + * Must have called makeGenericLibParts() before this function. + * @return XNODE* - the library nodes + */ + XNODE* makeLibraries(); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter_kicad.cpp b/eeschema/netlist_exporters/netlist_exporter_kicad.cpp new file mode 100644 index 00000000..e4b624cd --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_kicad.cpp @@ -0,0 +1,77 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 +#include +#include + +#include +#include "netlist_exporter_kicad.h" + +bool NETLIST_EXPORTER_KICAD::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) +{ +#if 0 + // Prepare list of nets generation + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + std::auto_ptr xroot( makeRoot() ); + + try + { + FILE_OUTPUTFORMATTER formatter( aOutFileName ); + + xroot->Format( &formatter, 0 ); + } +#else + try + { + FILE_OUTPUTFORMATTER formatter( aOutFileName ); + + Format( &formatter, GNL_ALL ); + } +#endif + + catch( const IO_ERROR& ioe ) + { + DisplayError( NULL, ioe.errorText ); + return false; + } + + return true; +} + + +void NETLIST_EXPORTER_KICAD::Format( OUTPUTFORMATTER* aOut, int aCtl ) +{ + // Prepare list of nets generation + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + std::auto_ptr xroot( makeRoot( aCtl ) ); + + xroot->Format( aOut, 0 ); +} diff --git a/eeschema/netlist_exporters/netlist_exporter_kicad.h b/eeschema/netlist_exporters/netlist_exporter_kicad.h new file mode 100644 index 00000000..433d12c4 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_kicad.h @@ -0,0 +1,63 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORTER_KICAD_H +#define NETLIST_EXPORTER_KICAD_H + +#include + +class OUTPUTFORMATTER; + +/** + * Class NETLIST_EXPORTER_KICAD + * generates the kicad netlist format supported by pcbnew. It is basically + * the generic netlist format just formatted slightly different. + */ +class NETLIST_EXPORTER_KICAD : public NETLIST_EXPORTER_GENERIC +{ +public: + NETLIST_EXPORTER_KICAD( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + NETLIST_EXPORTER_GENERIC( aMasterList, aLibs ) + { + } + + /** + * Function WriteNetlist + * writes to specified output file + */ + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); // OVERRIDE + + /** + * Function Format + * outputs this s-expression netlist into @a aOutputFormatter. + * @param aOutputFormatter is the destination of the serialization to text. + * @param aCtl is bit set composed by OR-ing together enum GNL bits, it allows ouputting + * a subset of the full document model. + * @throw IO_ERROR if any problems. + */ + void Format( OUTPUTFORMATTER* aOutputFormatter, int aCtl ); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.cpp b/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.cpp new file mode 100644 index 00000000..0aeaccc3 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.cpp @@ -0,0 +1,145 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 +#include +#include + +#include +#include +#include +#include + +#include +#include "netlist_exporter_orcadpcb2.h" + +bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) +{ + (void)aNetlistOptions; //unused + FILE* f = NULL; + wxString field; + wxString footprint; + int ret = 0; // zero now, OR in the sign bit on error + wxString netName; + + + if( ( f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == NULL ) + { + wxString msg; + msg.Printf( _( "Failed to create file '%s'" ), + GetChars( aOutFileName ) ); + DisplayError( NULL, msg ); + return false; + } + + std::vector< SCH_REFERENCE > cmpList; + + ret |= fprintf( f, "( { %s created %s }\n", + NETLIST_HEAD_STRING, TO_UTF8( DateAndTime() ) ); + + // Prepare list of nets generation + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + // Create netlist module section + m_ReferencesAlreadyFound.Clear(); + + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext() ) + { + for( EDA_ITEM* item = path->LastDrawList(); item; item = item->Next() ) + { + SCH_COMPONENT* comp = findNextComponentAndCreatePinList( item, path ); + + if( !comp ) + break; + + item = comp; + + // Get the Component FootprintFilter and put the component in + // cmpList if filter is present + LIB_PART* part = m_libs->FindLibPart( comp->GetPartName() ); + + if( part ) + { + if( part->GetFootPrints().GetCount() != 0 ) // Put in list + { + cmpList.push_back( SCH_REFERENCE( comp, part, *path ) ); + } + } + + if( !comp->GetField( FOOTPRINT )->IsVoid() ) + { + footprint = comp->GetField( FOOTPRINT )->GetText(); + footprint.Replace( wxT( " " ), wxT( "_" ) ); + } + else + footprint = wxT( "$noname" ); + + field = comp->GetRef( path ); + + ret |= fprintf( f, " ( %s %s", + TO_UTF8( comp->GetPath( path ) ), + TO_UTF8( footprint ) ); + + ret |= fprintf( f, " %s", TO_UTF8( field ) ); + + field = comp->GetField( VALUE )->GetText(); + field.Replace( wxT( " " ), wxT( "_" ) ); + ret |= fprintf( f, " %s", TO_UTF8( field ) ); + + ret |= fprintf( f, "\n" ); + + // Write pin list: + for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) + { + NETLIST_OBJECT* pin = m_SortedComponentPinList[ii]; + + if( !pin ) + continue; + + sprintPinNetName( netName, wxT( "N-%.6d" ), pin ); + + if( netName.IsEmpty() ) + netName = wxT( "?" ); + + netName.Replace( wxT( " " ), wxT( "_" ) ); + + ret |= fprintf( f, " ( %4.4s %s )\n", (char*) &pin->m_PinNum, + TO_UTF8( netName ) ); + } + + ret |= fprintf( f, " )\n" ); + } + } + + ret |= fprintf( f, ")\n*\n" ); + + fclose( f ); + + m_SortedComponentPinList.clear(); + return ret >= 0; +} diff --git a/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.h b/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.h new file mode 100644 index 00000000..06fcf10d --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_orcadpcb2.h @@ -0,0 +1,46 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORTER_ORCADPCB2_H +#define NETLIST_EXPORTER_ORCADPCB2_H + +#include "netlist_exporter.h" + +/** + * Class NETLIST_EXPORTER_ORCADPCB2 + * generates a netlist compatible with OrCAD + */ +class NETLIST_EXPORTER_ORCADPCB2 : public NETLIST_EXPORTER +{ +public: + NETLIST_EXPORTER_ORCADPCB2( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + NETLIST_EXPORTER( aMasterList, aLibs ) + { + } + + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.cpp b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp new file mode 100644 index 00000000..7158bd4d --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp @@ -0,0 +1,358 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 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 +#include +#include + +#include +#include +#include +#include +#include +#include "netlist_exporter_pspice.h" + +bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) +{ + FILE* f = NULL; + bool aUsePrefix = aNetlistOptions & NET_USE_X_PREFIX; + bool aUseNetcodeAsNetName = aNetlistOptions & NET_USE_NETCODES_AS_NETNAMES; + + int ret = 0; + int nbitems; + wxString text; + wxArrayString spiceCommandAtBeginFile; + wxArrayString spiceCommandAtEndFile; + wxString msg; + wxString netName; + + #define BUFYPOS_LEN 4 + wxChar bufnum[BUFYPOS_LEN + 1]; + std::vector pinSequence; // numeric indices into m_SortedComponentPinList + wxArrayString stdPinNameArray; // Array containing Standard Pin Names + wxString delimeters = wxT( "{:,; }" ); + wxString disableStr = wxT( "N" ); + + if( ( f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == NULL ) + { + wxString msg; + msg.Printf( _( "Failed to create file '%s'" ), + GetChars( aOutFileName ) ); + DisplayError( NULL, msg ); + return false; + } + + ret |= fprintf( f, "* %s\n\n", TO_UTF8( aOutFileName ) ); + ret |= fprintf( f, "* %s (Spice format) creation date: %s\n\n", + NETLIST_HEAD_STRING, TO_UTF8( DateAndTime() ) ); + + // Prepare list of nets generation (not used here, but... + for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) + m_masterList->GetItem( ii )->m_Flag = 0; + + ret |= fprintf( f, "* To exclude a component from the Spice Netlist add [Spice_Netlist_Enabled] user FIELD set to: N\n" ); + ret |= fprintf( f, "* To reorder the component spice node sequence add [Spice_Node_Sequence] user FIELD and define sequence: 2,1,0\n" ); + + // Create text list starting by [.-]pspice , or [.-]gnucap (simulator + // commands) and create text list starting by [+]pspice , or [+]gnucap + // (simulator commands) + bufnum[BUFYPOS_LEN] = 0; + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* sheet = sheetList.GetFirst(); sheet; sheet = sheetList.GetNext() ) + { + for( EDA_ITEM* item = sheet->LastDrawList(); item; item = item->Next() ) + { + size_t l1, l2; + wxChar ident; + + if( item->Type() != SCH_TEXT_T ) + continue; + + SCH_TEXT* drawText = (SCH_TEXT*) item; + + text = drawText->GetText(); + + if( text.IsEmpty() ) + continue; + + ident = text.GetChar( 0 ); + + if( ident != '.' && ident != '-' && ident != '+' ) + continue; + + text.Remove( 0, 1 ); // Remove the first char. + text.Remove( 6 ); // text contains 6 char. + text.MakeLower(); + + if( text != wxT( "pspice" ) && text != wxT( "gnucap" ) ) + continue; + + text = drawText->GetText().Mid( 7 ); + l1 = text.Length(); + text.Trim( false ); + l2 = text.Length(); + + if( l1 == l2 ) + continue; // no whitespace after ident text + + { + // Put the Y position as an ascii string, for sort by vertical + // position, using usual sort string by alphabetic value + int ypos = drawText->GetPosition().y; + + for( int ii = 0; ii < BUFYPOS_LEN; ii++ ) + { + bufnum[BUFYPOS_LEN - 1 - ii] = (ypos & 63) + ' '; + ypos >>= 6; + } + + // First BUFYPOS_LEN char are the Y position. + msg.Printf( wxT( "%s %s" ), bufnum, text.GetData() ); + + if( ident == '+' ) + spiceCommandAtEndFile.Add( msg ); + else + spiceCommandAtBeginFile.Add( msg ); + } + } + } + + // Print texts starting by [.-]pspice , ou [.-]gnucap (of course, without + // the Y position string) + nbitems = spiceCommandAtBeginFile.GetCount(); + + if( nbitems ) + { + spiceCommandAtBeginFile.Sort(); + + for( int ii = 0; ii < nbitems; ii++ ) + { + spiceCommandAtBeginFile[ii].Remove( 0, BUFYPOS_LEN ); + spiceCommandAtBeginFile[ii].Trim( true ); + spiceCommandAtBeginFile[ii].Trim( false ); + ret |= fprintf( f, "%s\n", TO_UTF8( spiceCommandAtBeginFile[ii] ) ); + } + } + ret |= fprintf( f, "\n" ); + + // Create component list + + m_ReferencesAlreadyFound.Clear(); + + for( SCH_SHEET_PATH* sheet = sheetList.GetFirst(); sheet; sheet = sheetList.GetNext() ) + { + ret |= fprintf( f, "* Sheet Name: %s\n", TO_UTF8( sheet->PathHumanReadable() ) ); + + for( EDA_ITEM* item = sheet->LastDrawList(); item; item = item->Next() ) + { + SCH_COMPONENT* comp = findNextComponentAndCreatePinList( item, sheet ); + + if( !comp ) + break; + + item = comp; + + // Reset NodeSeqIndex Count: + pinSequence.clear(); + + // Check to see if component should be removed from Spice Netlist: + SCH_FIELD* netlistEnabledField = comp->FindField( wxT( "Spice_Netlist_Enabled" ) ); + + if( netlistEnabledField ) + { + wxString netlistEnabled = netlistEnabledField->GetText(); + + if( netlistEnabled.CmpNoCase( disableStr ) == 0 ) + continue; + } + + // Check if Alternative Pin Sequence is Available: + SCH_FIELD* spiceSeqField = comp->FindField( wxT( "Spice_Node_Sequence" ) ); + + if( spiceSeqField ) + { + // Get String containing the Sequence of Nodes: + wxString nodeSeqIndexLineStr = spiceSeqField->GetText(); + + // Verify Field Exists and is not empty: + if( !nodeSeqIndexLineStr.IsEmpty() ) + { + + // Create an Array of Standard Pin Names from part definition: + stdPinNameArray.Clear(); + + for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) + { + NETLIST_OBJECT* pin = m_SortedComponentPinList[ii]; + + if( !pin ) + continue; + + stdPinNameArray.Add( pin->GetPinNumText() ); + } + + // Get Alt Pin Name Array From User: + wxStringTokenizer tkz( nodeSeqIndexLineStr, delimeters ); + + while( tkz.HasMoreTokens() ) + { + wxString pinIndex = tkz.GetNextToken(); + int seq; + + // Find PinName In Standard List assign Standard List Index to Name: + seq = stdPinNameArray.Index(pinIndex); + + if( seq != wxNOT_FOUND ) + { + pinSequence.push_back( seq ); + } + } + + } + } + + //Get Standard Reference Designator: + wxString RefName = comp->GetRef( sheet ); + + //Conditionally add Prefix only for devices that begin with U or IC: + if( aUsePrefix ) + { + if( RefName.StartsWith( wxT( "U" ) ) || RefName.StartsWith( wxT( "IC" ) ) ) + RefName = wxT( "X" ) + RefName; + } + + ret |= fprintf( f, "%s ", TO_UTF8( RefName ) ); + + // Write pin list: + int activePinIndex = 0; + + for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) + { + // Case of Alt Sequence definition with Unused/Invalid Node index: + // Valid used Node Indexes are in the set + // {0,1,2,...m_SortedComponentPinList.size()-1} + if( pinSequence.size() ) + { + // All Vector values must be less <= max package size + // And Total Vector size should be <= package size + if( ( (unsigned) pinSequence[ii] < m_SortedComponentPinList.size() ) + && ( ii < pinSequence.size() ) ) + { + // Case of Alt Pin Sequence in control good Index: + activePinIndex = pinSequence[ii]; + } + else + { + // Case of Alt Pin Sequence in control Bad Index or not using all + // pins for simulation: + continue; + } + } + // Case of Standard Pin Sequence in control: + else + { + activePinIndex = ii; + } + + NETLIST_OBJECT* pin = m_SortedComponentPinList[activePinIndex]; + + if( !pin ) + continue; + + sprintPinNetName( netName , wxT( "N-%.6d" ), pin, aUseNetcodeAsNetName ); + + //Replace parenthesis with underscore to prevent parse issues with Simulators: + netName.Replace( wxT( "(" ), wxT( "_" ) ); + netName.Replace( wxT( ")" ), wxT( "_" ) ); + + if( netName.IsEmpty() ) + netName = wxT( "?" ); + + ret |= fprintf( f, " %s", TO_UTF8( netName ) ); + } + + // Get Component Value Name: + wxString CompValue = comp->GetField( VALUE )->GetText(); + + // Check if Override Model Name is Provided: + SCH_FIELD* spiceModelField = comp->FindField( wxT( "spice_model" ) ); + + if( spiceModelField ) + { + // Get Model Name String: + wxString ModelNameStr = spiceModelField->GetText(); + + // Verify Field Exists and is not empty: + if( !ModelNameStr.IsEmpty() ) + CompValue = ModelNameStr; + } + + // Print Component Value: + ret |= fprintf( f, " %s\t\t",TO_UTF8( CompValue ) ); + + // Show Seq Spec on same line as component using line-comment ";": + for( unsigned i = 0; i < pinSequence.size(); ++i ) + { + if( i==0 ) + ret |= fprintf( f, ";Node Sequence Spec.<" ); + + ret |= fprintf( f, "%s", TO_UTF8( stdPinNameArray.Item( pinSequence[i] ) ) ); + + if( i < pinSequence.size()-1 ) + ret |= fprintf( f, "," ); + else + ret |= fprintf( f, ">" ); + } + + // Next Netlist line record: + ret |= fprintf( f, "\n" ); + } + } + + m_SortedComponentPinList.clear(); + + // Print texts starting with [+]pspice or [+]gnucap + nbitems = spiceCommandAtEndFile.GetCount(); + + if( nbitems ) + { + ret |= fprintf( f, "\n" ); + spiceCommandAtEndFile.Sort(); + + for( int ii = 0; ii < nbitems; ii++ ) + { + spiceCommandAtEndFile[ii].Remove( 0, +BUFYPOS_LEN ); + spiceCommandAtEndFile[ii].Trim( true ); + spiceCommandAtEndFile[ii].Trim( false ); + ret |= fprintf( f, "%s\n", TO_UTF8( spiceCommandAtEndFile[ii] ) ); + } + } + + ret |= fprintf( f, "\n.end\n" ); + fclose( f ); + + return ret >= 0; +} diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.h b/eeschema/netlist_exporters/netlist_exporter_pspice.h new file mode 100644 index 00000000..c57938f6 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.h @@ -0,0 +1,50 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2013 jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2015 KiCad Developers + * + * 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 NETLIST_EXPORTER_PSPICE_H +#define NETLIST_EXPORTER_PSPICE_H + +#include "netlist_exporter.h" + +/** + * Class NETLIST_EXPORTER_PSPICE + * generates a PSPICE compatible netlist + */ +class NETLIST_EXPORTER_PSPICE : public NETLIST_EXPORTER +{ +public: + NETLIST_EXPORTER_PSPICE( NETLIST_OBJECT_LIST* aMasterList, PART_LIBS* aLibs ) : + NETLIST_EXPORTER( aMasterList, aLibs ) + { + } + + /** + * Function WriteNetlist + * writes to specified output file + */ + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); +}; + +#endif diff --git a/eeschema/onleftclick.cpp b/eeschema/onleftclick.cpp new file mode 100644 index 00000000..35ba87d4 --- /dev/null +++ b/eeschema/onleftclick.cpp @@ -0,0 +1,407 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file eeschema/onleftclick.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // fo class SCHLIB_FILTER to filter power parts + + +// TODO(hzeller): These pairs of elmenets should be represented by an object, but don't want +// to refactor too much right now to not get in the way with other code changes. +static wxArrayString s_CmpNameList; +static int s_CmpLastUnit; + +static wxArrayString s_PowerNameList; +static int s_LastPowerUnit; + + +void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) +{ + SCH_ITEM* item = GetScreen()->GetCurItem(); + wxPoint gridPosition = GetGridPosition( aPosition ); + + if( ( GetToolId() == ID_NO_TOOL_SELECTED ) || ( item && item->GetFlags() ) ) + { + m_canvas->SetAutoPanRequest( false ); + SetRepeatItem( NULL ); + + if( item && item->GetFlags() ) + { + switch( item->Type() ) + { + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_TEXT_T: + case SCH_SHEET_PIN_T: + case SCH_SHEET_T: + case SCH_BUS_WIRE_ENTRY_T: + case SCH_BUS_BUS_ENTRY_T: + case SCH_JUNCTION_T: + case SCH_COMPONENT_T: + case SCH_FIELD_T: + case SCH_BITMAP_T: + case SCH_NO_CONNECT_T: + addCurrentItemToList(); + return; + + case SCH_LINE_T: // May already be drawing segment. + break; + + default: + wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick error. Item type <" ) + + item->GetClass() + wxT( "> is already being edited." ) ); + item->ClearFlags(); + break; + } + } + else + { + item = LocateAndShowItem( aPosition ); + } + } + + switch( GetToolId() ) + { + case ID_NO_TOOL_SELECTED: + break; + + case ID_HIERARCHY_PUSH_POP_BUTT: + if( ( item && item->GetFlags() ) || ( g_RootSheet->CountSheets() == 0 ) ) + break; + + item = LocateAndShowItem( aPosition, SCH_COLLECTOR::SheetsOnly ); + + if( item ) // The user has clicked on a sheet: this is an enter sheet command + { + m_CurrentSheet->Push( (SCH_SHEET*) item ); + DisplayCurrentSheet(); + } + else if( m_CurrentSheet->Last() != g_RootSheet ) + { // The user has clicked ouside a sheet:this is an leave sheet command + m_CurrentSheet->Pop(); + DisplayCurrentSheet(); + } + break; + + case ID_NOCONN_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + if( GetScreen()->GetItem( gridPosition, 0, SCH_NO_CONNECT_T ) == NULL ) + { + SCH_NO_CONNECT* no_connect = AddNoConnect( aDC, gridPosition ); + SetRepeatItem( no_connect ); + GetScreen()->SetCurItem( no_connect ); + m_canvas->SetAutoPanRequest( true ); + } + } + else + { + addCurrentItemToList(); + } + break; + + case ID_JUNCTION_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + if( GetScreen()->GetItem( gridPosition, 0, SCH_JUNCTION_T ) == NULL ) + { + SCH_JUNCTION* junction = AddJunction( aDC, gridPosition, true ); + SetRepeatItem( junction ); + GetScreen()->SetCurItem( junction ); + m_canvas->SetAutoPanRequest( true ); + } + } + else + { + addCurrentItemToList(); + } + break; + + case ID_WIRETOBUS_ENTRY_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + CreateBusWireEntry(); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_BUSTOBUS_ENTRY_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + CreateBusBusEntry(); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_SCHEMATIC_DELETE_ITEM_BUTT: + DeleteItemAtCrossHair( aDC ); + break; + + case ID_WIRE_BUTT: + BeginSegment( aDC, LAYER_WIRE ); + m_canvas->SetAutoPanRequest( true ); + break; + + case ID_BUS_BUTT: + BeginSegment( aDC, LAYER_BUS ); + m_canvas->SetAutoPanRequest( true ); + break; + + case ID_LINE_COMMENT_BUTT: + BeginSegment( aDC, LAYER_NOTES ); + m_canvas->SetAutoPanRequest( true ); + break; + + case ID_TEXT_COMMENT_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_NOTES ) ); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_ADD_IMAGE_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + GetScreen()->SetCurItem( CreateNewImage( aDC ) ); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_LABEL_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_LOCLABEL ) ); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_GLABEL_BUTT: + case ID_HIERLABEL_BUTT: + if( (item == NULL) || (item->GetFlags() == 0) ) + { + if( GetToolId() == ID_GLABEL_BUTT ) + GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_GLOBLABEL ) ); + + if( GetToolId() == ID_HIERLABEL_BUTT ) + GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_HIERLABEL ) ); + + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_SHEET_SYMBOL_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + item = CreateSheet( aDC ); + + if( item != NULL ) + { + GetScreen()->SetCurItem( item ); + m_canvas->SetAutoPanRequest( true ); + } + } + else + { + addCurrentItemToList(); + } + break; + + case ID_IMPORT_HLABEL_BUTT: + case ID_SHEET_PIN_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + item = LocateAndShowItem( aPosition, SCH_COLLECTOR::SheetsAndSheetLabels ); + + if( item == NULL ) + break; + + if( (item->Type() == SCH_SHEET_T) && (item->GetFlags() == 0) ) + { + if( GetToolId() == ID_IMPORT_HLABEL_BUTT ) + GetScreen()->SetCurItem( ImportSheetPin( (SCH_SHEET*) item, aDC ) ); + else + GetScreen()->SetCurItem( CreateSheetPin( (SCH_SHEET*) item, aDC ) ); + } + else if( (item->Type() == SCH_SHEET_PIN_T) && (item->GetFlags() != 0) ) + { + addCurrentItemToList(); + } + break; + + case ID_SCH_PLACE_COMPONENT: + if( (item == NULL) || (item->GetFlags() == 0) ) + { + GetScreen()->SetCurItem( Load_Component( aDC, NULL, + s_CmpNameList, s_CmpLastUnit, true ) ); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + case ID_PLACE_POWER_BUTT: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + SCHLIB_FILTER filter; + filter.FilterPowerParts( true ); + GetScreen()->SetCurItem( Load_Component( aDC, &filter, + s_PowerNameList, s_LastPowerUnit, false ) ); + m_canvas->SetAutoPanRequest( true ); + } + else + { + addCurrentItemToList(); + } + break; + + default: + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick invalid tool ID <" ) + + wxString::Format( wxT( "%d> selected." ), GetToolId() ) ); + } +} + + +/** + * Function OnLeftDClick + * called on a double click event from the drawpanel mouse handler + * if an editable item is found (text, component) + * Call the suitable dialog editor. + * Id a create command is in progress: + * validate and finish the command + */ +void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) + +{ + EDA_ITEM* item = GetScreen()->GetCurItem(); + + switch( GetToolId() ) + { + case ID_NO_TOOL_SELECTED: + if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) + { + item = LocateAndShowItem( aPosition ); + } + + if( ( item == NULL ) || ( item->GetFlags() != 0 ) ) + break; + + switch( item->Type() ) + { + case SCH_SHEET_T: + m_CurrentSheet->Push( (SCH_SHEET*) item ); + DisplayCurrentSheet(); + break; + + case SCH_COMPONENT_T: + EditComponent( (SCH_COMPONENT*) item ); + GetCanvas()->MoveCursorToCrossHair(); + + if( item->GetFlags() == 0 ) + GetScreen()->SetCurItem( NULL ); + + GetCanvas()->Refresh(); + break; + + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + EditSchematicText( (SCH_TEXT*) item ); + break; + + case SCH_BITMAP_T: + EditImage( (SCH_BITMAP*) item ); + break; + + case SCH_FIELD_T: + EditComponentFieldText( (SCH_FIELD*) item ); + GetCanvas()->MoveCursorToCrossHair(); + break; + + case SCH_MARKER_T: + ( (SCH_MARKER*) item )->DisplayMarkerInfo( this ); + break; + + default: + break; + } + + break; + + case ID_BUS_BUTT: + case ID_WIRE_BUTT: + case ID_LINE_COMMENT_BUTT: + if( item && item->IsNew() ) + EndSegment( aDC ); + + break; + } +} diff --git a/eeschema/onrightclick.cpp b/eeschema/onrightclick.cpp new file mode 100644 index 00000000..442e2412 --- /dev/null +++ b/eeschema/onrightclick.cpp @@ -0,0 +1,927 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2014 Wayne Stambaugh + * Copyright (C) 2004-2014 KiCad Developers, see change_log.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 + */ + +/** + * @file eeschema/onrightclick.cpp + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void AddMenusForBlock( wxMenu* PopMenu, SCH_EDIT_FRAME* frame ); +static void AddMenusForWire( wxMenu* PopMenu, SCH_LINE* Wire, SCH_EDIT_FRAME* frame ); +static void AddMenusForBus( wxMenu* PopMenu, SCH_LINE* Bus, SCH_EDIT_FRAME* frame ); +static void AddMenusForHierchicalSheet( wxMenu* PopMenu, SCH_SHEET* Sheet ); +static void AddMenusForSheetPin( wxMenu* PopMenu, SCH_SHEET_PIN* PinSheet ); +static void AddMenusForText( wxMenu* PopMenu, SCH_TEXT* Text ); +static void AddMenusForLabel( wxMenu* PopMenu, SCH_LABEL* Label ); +static void AddMenusForGLabel( wxMenu* PopMenu, SCH_GLOBALLABEL* GLabel ); +static void AddMenusForHLabel( wxMenu* PopMenu, SCH_HIERLABEL* GLabel ); +static void AddMenusForEditComponent( wxMenu* PopMenu, SCH_COMPONENT* Component, PART_LIBS* aLibs ); +static void AddMenusForComponent( wxMenu* PopMenu, SCH_COMPONENT* Component, PART_LIBS* aLibs ); +static void AddMenusForComponentField( wxMenu* PopMenu, SCH_FIELD* Field ); +static void AddMenusForMarkers( wxMenu* aPopMenu, SCH_MARKER* aMarker, SCH_EDIT_FRAME* aFrame ); +static void AddMenusForBitmap( wxMenu* aPopMenu, SCH_BITMAP * aBitmap ); +static void AddMenusForBusEntry( wxMenu* aPopMenu, SCH_BUS_ENTRY_BASE * aBusEntry ); + + +bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu ) +{ + SCH_ITEM* item = GetScreen()->GetCurItem(); + bool blockActive = GetScreen()->IsBlockActive(); + wxString msg; + + // Do not start a block command on context menu. + m_canvas->SetCanStartBlock( -1 ); + + if( blockActive ) + { + AddMenusForBlock( PopMenu, this ); + PopMenu->AppendSeparator(); + + // If we have a block containing only one main element + // we append its edition submenu + if( item != NULL ) + { + switch( item->Type() ) + { + case SCH_COMPONENT_T: + AddMenusForEditComponent( PopMenu, (SCH_COMPONENT *) item, Prj().SchLibs() ); + PopMenu->AppendSeparator(); + break; + + case SCH_TEXT_T: + msg = AddHotkeyName( _( "Edit Text" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + PopMenu->AppendSeparator(); + break; + + case SCH_LABEL_T: + msg = AddHotkeyName( _( "Edit Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + PopMenu->AppendSeparator(); + break; + + case SCH_GLOBAL_LABEL_T: + msg = AddHotkeyName( _( "Edit Global Label" ), g_Schematic_Hokeys_Descr, + HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + PopMenu->AppendSeparator(); + break; + + case SCH_HIERARCHICAL_LABEL_T: + msg = AddHotkeyName( _( "Edit Hierarchical Label" ), g_Schematic_Hokeys_Descr, + HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + PopMenu->AppendSeparator(); + break; + + case SCH_BITMAP_T: + msg = AddHotkeyName( _( "Edit Image" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( image_xpm ) ); + PopMenu->AppendSeparator(); + break; + + default: + break; + } + } + return true; + } + + // Try to locate items at cursor position. + if( (item == NULL) || (item->GetFlags() == 0) ) + { + item = LocateAndShowItem( aPosition, SCH_COLLECTOR::AllItemsButPins ); + + // If the clarify item selection context menu is aborted, don't show the context menu. + if( item == NULL && m_canvas->GetAbortRequest() ) + { + m_canvas->SetAbortRequest( false ); + return false; + } + } + + // If a command is in progress: add "cancel" and "end tool" menu + // If + if( GetToolId() != ID_NO_TOOL_SELECTED ) + { + if( item && item->GetFlags() ) + { + AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), + KiBitmap( cancel_xpm ) ); + } + else + { + AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "End Tool" ), + KiBitmap( cursor_xpm ) ); + } + + PopMenu->AppendSeparator(); + + switch( GetToolId() ) + { + case ID_WIRE_BUTT: + AddMenusForWire( PopMenu, NULL, this ); + if( item == NULL ) + PopMenu->AppendSeparator(); + break; + + case ID_BUS_BUTT: + AddMenusForBus( PopMenu, NULL, this ); + if( item == NULL ) + PopMenu->AppendSeparator(); + break; + + default: + break; + } + } + else + { + if( item && item->GetFlags() ) + { + AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), + KiBitmap( cancel_xpm ) ); + PopMenu->AppendSeparator(); + } + } + + if( item == NULL ) + { + if( m_CurrentSheet->Last() != g_RootSheet ) + { + msg = AddHotkeyName( _( "Leave Sheet" ), g_Schematic_Hokeys_Descr, HK_LEAVE_SHEET ); + AddMenuItem( PopMenu, ID_POPUP_SCH_LEAVE_SHEET, msg, + KiBitmap( leave_sheet_xpm ) ); + PopMenu->AppendSeparator(); + } + return true; + } + + bool is_new = item->IsNew(); + + switch( item->Type() ) + { + case SCH_NO_CONNECT_T: + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, _( "Delete No Connect" ), + KiBitmap( delete_xpm ) ); + break; + + case SCH_JUNCTION_T: + addJunctionMenuEntries( PopMenu, (SCH_JUNCTION*) item ); + break; + + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + AddMenusForBusEntry( PopMenu, static_cast( item ) ); + break; + + case SCH_MARKER_T: + AddMenusForMarkers( PopMenu, (SCH_MARKER*) item, this ); + break; + + case SCH_TEXT_T: + AddMenusForText( PopMenu, (SCH_TEXT*) item ); + break; + + case SCH_LABEL_T: + AddMenusForLabel( PopMenu, (SCH_LABEL*) item ); + break; + + case SCH_GLOBAL_LABEL_T: + AddMenusForGLabel( PopMenu, (SCH_GLOBALLABEL*) item ); + break; + + case SCH_HIERARCHICAL_LABEL_T: + AddMenusForHLabel( PopMenu, (SCH_HIERLABEL*) item ); + break; + + case SCH_FIELD_T: + AddMenusForComponentField( PopMenu, (SCH_FIELD*) item ); + break; + + case SCH_COMPONENT_T: + AddMenusForComponent( PopMenu, (SCH_COMPONENT*) item, Prj().SchLibs() ); + break; + + case SCH_BITMAP_T: + AddMenusForBitmap( PopMenu, (SCH_BITMAP*) item ); + break; + + case SCH_LINE_T: + switch( item->GetLayer() ) + { + case LAYER_WIRE: + AddMenusForWire( PopMenu, (SCH_LINE*) item, this ); + break; + + case LAYER_BUS: + AddMenusForBus( PopMenu, (SCH_LINE*) item, this ); + break; + + default: + if( is_new ) + AddMenuItem( PopMenu, ID_POPUP_END_LINE, _( "End Drawing" ), + KiBitmap( checked_ok_xpm ) ); + + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, _( "Delete Drawing" ), + KiBitmap( delete_xpm ) ); + break; + } + break; + + case SCH_SHEET_T: + AddMenusForHierchicalSheet( PopMenu, (SCH_SHEET*) item ); + break; + + case SCH_SHEET_PIN_T: + AddMenusForSheetPin( PopMenu, (SCH_SHEET_PIN*) item ); + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Cannot create context menu for unknown type %d" ), + item->Type() ) ); + break; + } + + PopMenu->AppendSeparator(); + return true; +} + + +void AddMenusForComponentField( wxMenu* PopMenu, SCH_FIELD* Field ) +{ + wxString msg, name; + + if( !Field->GetFlags() ) + { + switch( Field->GetId() ) + { + case REFERENCE: name = _( "Move Reference" ); break; + case VALUE: name = _( "Move Value" ); break; + case FOOTPRINT: name = _( "Move Footprint Field" ); break; + default: name = _( "Move Field" ); break; + } + + msg = AddHotkeyName( name, g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_text_xpm ) ); + } + + switch( Field->GetId() ) + { + case REFERENCE: name = _( "Rotate Reference" ); break; + case VALUE: name = _( "Rotate Value" ); break; + case FOOTPRINT: name = _( "Rotate Footprint Field" ); break; + default: name = _( "Rotate Field" ); break; + } + + msg = AddHotkeyName( name, g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_field_xpm ) ); + + // Ref, value and footprint have specific hotkeys. Show the specific hotkey: + hotkey_id_commnand id; + switch( Field->GetId() ) + { + case REFERENCE: + id = HK_EDIT_COMPONENT_REFERENCE; + name = _( "Edit Reference" ); + break; + case VALUE: + id = HK_EDIT_COMPONENT_VALUE; + name = _( "Edit Value" ); + break; + case FOOTPRINT: + id = HK_EDIT_COMPONENT_FOOTPRINT; + name = _( "Edit Footprint Field" ); + break; + default: + id = HK_EDIT; + name = _( "Edit Field" ); + break; + } + msg = AddHotkeyName( name, g_Schematic_Hokeys_Descr, id ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); +} + + +void AddMenusForComponent( wxMenu* PopMenu, SCH_COMPONENT* Component, PART_LIBS* aLibs ) +{ + if( Component->Type() != SCH_COMPONENT_T ) + { + wxASSERT( 0 ); + return; + } + + wxString msg; + LIB_ALIAS* libEntry = aLibs->FindLibraryEntry( Component->GetPartName() ); + + if( !Component->GetFlags() ) + { + msg.Printf( _( "Move Component %s" ), + GetChars( Component->GetField( REFERENCE )->GetText() ) ); + msg = AddHotkeyName( msg, g_Schematic_Hokeys_Descr, HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_xpm ) ); + msg = AddHotkeyName( _( "Drag Component" ), g_Schematic_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_xpm ) ); + } + + wxMenu* orientmenu = new wxMenu; + msg = AddHotkeyName( _( "Rotate Clockwise" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( orientmenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_cw_xpm ) ); + AddMenuItem( orientmenu, ID_SCH_ROTATE_COUNTERCLOCKWISE, _( "Rotate Counterclockwise" ), + KiBitmap( rotate_ccw_xpm ) ); + msg = AddHotkeyName( _( "Mirror --" ), g_Schematic_Hokeys_Descr, HK_MIRROR_X ); + AddMenuItem( orientmenu, ID_SCH_MIRROR_X, msg, KiBitmap( mirror_v_xpm ) ); + msg = AddHotkeyName( _( "Mirror ||" ), g_Schematic_Hokeys_Descr, HK_MIRROR_Y ); + AddMenuItem( orientmenu, ID_SCH_MIRROR_Y, msg, KiBitmap( mirror_h_xpm ) ); + msg = AddHotkeyName( _( "Normal" ), g_Schematic_Hokeys_Descr, HK_ORIENT_NORMAL_COMPONENT ); + AddMenuItem( orientmenu, ID_SCH_ORIENT_NORMAL, msg, KiBitmap( normal_xpm ) ); + AddMenuItem( PopMenu, orientmenu, ID_POPUP_SCH_GENERIC_ORIENT_CMP, + _( "Orient Component" ), KiBitmap( orient_xpm ) ); + + AddMenusForEditComponent( PopMenu, Component, aLibs ); + + if( !Component->GetFlags() ) + { + msg = AddHotkeyName( _( "Copy Component" ), g_Schematic_Hokeys_Descr, + HK_COPY_COMPONENT_OR_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_COPY_ITEM, msg, KiBitmap( copy_button_xpm ) ); + msg = AddHotkeyName( _( "Delete Component" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE_CMP, msg, KiBitmap( delete_xpm ) ); + } + + if( libEntry && !libEntry->GetDocFileName().IsEmpty() ) + AddMenuItem( PopMenu, ID_POPUP_SCH_DISPLAYDOC_CMP, _( "Doc" ), KiBitmap( datasheet_xpm ) ); +} + + +void AddMenusForEditComponent( wxMenu* PopMenu, SCH_COMPONENT* Component, PART_LIBS* aLibs ) +{ + if( Component->Type() != SCH_COMPONENT_T ) + { + wxASSERT( 0 ); + return; + } + + wxString msg; + LIB_PART* part = NULL; + LIB_ALIAS* libEntry = aLibs->FindLibraryEntry( Component->GetPartName() ); + + if( libEntry ) + part = libEntry->GetPart(); + + wxMenu* editmenu = new wxMenu; + msg = AddHotkeyName( _( "Edit" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( editmenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_component_xpm ) ); + + if( part && part->IsNormal() ) + { + msg = AddHotkeyName( _( "Value" ), g_Schematic_Hokeys_Descr, + HK_EDIT_COMPONENT_VALUE ); + AddMenuItem( editmenu, ID_SCH_EDIT_COMPONENT_VALUE, msg, + KiBitmap( edit_comp_value_xpm ) ); + + msg = AddHotkeyName( _( "Reference" ), g_Schematic_Hokeys_Descr, + HK_EDIT_COMPONENT_REFERENCE ); + AddMenuItem( editmenu, ID_SCH_EDIT_COMPONENT_REFERENCE, msg, + KiBitmap( edit_comp_ref_xpm ) ); + + msg = AddHotkeyName( _( "Footprint" ), g_Schematic_Hokeys_Descr, + HK_EDIT_COMPONENT_FOOTPRINT ); + AddMenuItem( editmenu, ID_SCH_EDIT_COMPONENT_FOOTPRINT, msg, + KiBitmap( edit_comp_footprint_xpm ) ); + } + + if( part && part->HasConversion() ) + AddMenuItem( editmenu, ID_POPUP_SCH_EDIT_CONVERT_CMP, _( "Convert" ), + KiBitmap( component_select_alternate_shape_xpm ) ); + + if( part && part->GetUnitCount() >= 2 ) + { + wxMenu* sel_unit_menu = new wxMenu; int ii; + + for( ii = 0; ii < part->GetUnitCount(); ii++ ) + { + wxString num_unit; + int unit = Component->GetUnit(); + num_unit.Printf( _( "Unit %s" ), GetChars( LIB_PART::SubReference( ii + 1, false ) ) ); + wxMenuItem * item = sel_unit_menu->Append( ID_POPUP_SCH_SELECT_UNIT1 + ii, + num_unit, wxEmptyString, + wxITEM_CHECK ); + if( unit == ii + 1 ) + item->Check(true); + + // The ID max for these submenus is ID_POPUP_SCH_SELECT_UNIT_CMP_MAX + // See eeschema_id to modify this value. + if( ii >= (ID_POPUP_SCH_SELECT_UNIT_CMP_MAX - ID_POPUP_SCH_SELECT_UNIT1) ) + break; // We have used all IDs for these submenus + } + + AddMenuItem( editmenu, sel_unit_menu, ID_POPUP_SCH_SELECT_UNIT_CMP, + _( "Unit" ), KiBitmap( component_select_unit_xpm ) ); + } + + if( !Component->GetFlags() ) + { + msg = AddHotkeyName( _( "Edit with Library Editor" ), g_Schematic_Hokeys_Descr, + HK_EDIT_COMPONENT_WITH_LIBEDIT ); + AddMenuItem( editmenu, ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP, + msg, KiBitmap( libedit_xpm ) ); + } + + AddMenuItem( PopMenu, editmenu, ID_SCH_EDIT_ITEM, + _( "Edit Component" ), KiBitmap( edit_component_xpm ) ); +} + + +void AddMenusForGLabel( wxMenu* PopMenu, SCH_GLOBALLABEL* GLabel ) +{ + wxMenu* menu_change_type = new wxMenu; + wxString msg; + + if( !GLabel->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Global Label" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Drag Global Label" ), g_Schematic_Hokeys_Descr, + HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Copy Global Label" ), g_Schematic_Hokeys_Descr, + HK_COPY_COMPONENT_OR_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_COPY_ITEM, msg, KiBitmap( copy_button_xpm ) ); + } + + msg = AddHotkeyName( _( "Rotate Global Label" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_glabel_xpm ) ); + msg = AddHotkeyName( _( "Edit Global Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + msg = AddHotkeyName( _( "Delete Global Label" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_text_xpm ) ); + + // add menu change type text (to label, glabel, text): + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_HLABEL, + _( "Change to Hierarchical Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_LABEL, + _( "Change to Label" ), KiBitmap( glabel2label_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT, + _( "Change to Text" ), KiBitmap( glabel2text_xpm ) ); + AddMenuItem( PopMenu, menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT, + _( "Change Type" ), KiBitmap( gl_change_xpm ) ); +} + + +void AddMenusForHLabel( wxMenu* PopMenu, SCH_HIERLABEL* HLabel ) +{ + wxMenu* menu_change_type = new wxMenu; + wxString msg; + + if( !HLabel->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Hierarchical Label" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Drag Hierarchical Label" ), g_Schematic_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Copy Hierarchical Label" ), g_Schematic_Hokeys_Descr, + HK_COPY_COMPONENT_OR_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_COPY_ITEM, msg, KiBitmap( copy_button_xpm ) ); + } + + msg = AddHotkeyName( _( "Rotate Hierarchical Label" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_glabel_xpm ) ); + msg = AddHotkeyName( _( "Edit Hierarchical Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + msg = AddHotkeyName( _( "Delete Hierarchical Label" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_text_xpm ) ); + + // add menu change type text (to label, glabel, text): + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_LABEL, + _( "Change to Label" ), KiBitmap( glabel2label_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT, + _( "Change to Text" ), KiBitmap( glabel2text_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_GLABEL, + _( "Change to Global Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( PopMenu, menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT, + _( "Change Type" ), KiBitmap( gl_change_xpm ) ); +} + + +void AddMenusForLabel( wxMenu* PopMenu, SCH_LABEL* Label ) +{ + wxMenu* menu_change_type = new wxMenu; + wxString msg; + + if( !Label->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Label" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Drag Label" ), g_Schematic_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Copy Label" ), g_Schematic_Hokeys_Descr, + HK_COPY_COMPONENT_OR_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_COPY_ITEM, msg, KiBitmap( copy_button_xpm ) ); + } + + msg = AddHotkeyName( _( "Rotate Label" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_ccw_xpm ) ); + msg = AddHotkeyName( _( "Edit Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + msg = AddHotkeyName( _( "Delete Label" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_text_xpm ) ); + + // add menu change type text (to label, glabel, text): + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_HLABEL, + _( "Change to Hierarchical Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT, + _( "Change to Text" ), KiBitmap( label2text_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_GLABEL, + _( "Change to Global Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( PopMenu, menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT, + _( "Change Type" ), KiBitmap( gl_change_xpm ) ); +} + + +void AddMenusForText( wxMenu* PopMenu, SCH_TEXT* Text ) +{ + wxString msg; + wxMenu* menu_change_type = new wxMenu; + + if( !Text->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Text" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_text_xpm ) ); + msg = AddHotkeyName( _( "Copy Text" ), g_Schematic_Hokeys_Descr, + HK_COPY_COMPONENT_OR_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_COPY_ITEM, msg, KiBitmap( copy_button_xpm ) ); + } + + msg = AddHotkeyName( _( "Rotate Text" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_ccw_xpm ) ); + msg = AddHotkeyName( _( "Edit Text" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); + msg = AddHotkeyName( _( "Delete Text" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_text_xpm ) ); + + /* add menu change type text (to label, glabel, text), + * but only if this is a single line text + */ + if( Text->GetText().Find( wxT( "\n" ) ) == wxNOT_FOUND ) + { + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_LABEL, + _( "Change to Label" ), KiBitmap( label2text_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_HLABEL, + _( "Change to Hierarchical Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_GLABEL, + _( "Change to Global Label" ), KiBitmap( label2glabel_xpm ) ); + AddMenuItem( PopMenu, menu_change_type, ID_POPUP_SCH_CHANGE_TYPE_TEXT, + _( "Change Type" ), KiBitmap( gl_change_xpm ) ); + } +} + + +void SCH_EDIT_FRAME::addJunctionMenuEntries( wxMenu* aMenu, SCH_JUNCTION* aJunction ) +{ + wxString msg; + SCH_SCREEN* screen = GetScreen(); + + msg = AddHotkeyName( _( "Delete Junction" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( aMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_xpm ) ); + + if( !aJunction->IsNew() ) + { + if( m_collectedItems.IsDraggableJunction() ) + AddMenuItem( aMenu, ID_SCH_DRAG_ITEM, _( "Drag Junction" ), KiBitmap( move_xpm ) ); + + if( screen->GetWire( aJunction->GetPosition(), EXCLUDE_END_POINTS_T ) ) + AddMenuItem( aMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Wire" ), + KiBitmap( break_line_xpm ) ); + } + + if( screen->GetWireOrBus( aJunction->GetPosition() ) ) + { + AddMenuItem( aMenu, ID_POPUP_SCH_DELETE_NODE, _( "Delete Node" ), + KiBitmap( delete_node_xpm ) ); + AddMenuItem( aMenu, ID_POPUP_SCH_DELETE_CONNECTION, _( "Delete Connection" ), + KiBitmap( delete_connection_xpm ) ); + } +} + + +void AddMenusForWire( wxMenu* PopMenu, SCH_LINE* Wire, SCH_EDIT_FRAME* frame ) +{ + SCH_SCREEN* screen = frame->GetScreen(); + wxPoint pos = frame->GetCrossHairPosition(); + wxString msg; + + if( Wire == NULL ) + { + msg = AddHotkeyName( _( "Begin Wire" ), g_Schematic_Hokeys_Descr, HK_BEGIN_WIRE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_BEGIN_WIRE, msg, KiBitmap( add_line_xpm ) ); + return; + } + + bool is_new = Wire->IsNew(); + if( is_new ) + { + msg = AddHotkeyName( _( "Wire End" ), g_Schematic_Hokeys_Descr, HK_END_CURR_LINEWIREBUS ); + AddMenuItem( PopMenu, ID_POPUP_END_LINE, msg, KiBitmap( checked_ok_xpm ) ); + return; + } + + msg = AddHotkeyName( _( "Drag Wire" ), g_Schematic_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_track_xpm ) ); + PopMenu->AppendSeparator(); + msg = AddHotkeyName( _( "Delete Wire" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE_NODE, _( "Delete Node" ), + KiBitmap( delete_node_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE_CONNECTION, _( "Delete Connection" ), + KiBitmap( delete_connection_xpm ) ); + + SCH_LINE* line = screen->GetWireOrBus( frame->GetCrossHairPosition() ); + + if( line && !line->IsEndPoint( frame->GetCrossHairPosition() ) ) + AddMenuItem( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Wire" ), + KiBitmap( break_line_xpm ) ); + + PopMenu->AppendSeparator(); + + msg = AddHotkeyName( _( "Add Junction" ), g_Schematic_Hokeys_Descr, HK_ADD_JUNCTION ); + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_JUNCTION, msg, KiBitmap( add_junction_xpm ) ); + msg = AddHotkeyName( _( "Add Label" ), g_Schematic_Hokeys_Descr, HK_ADD_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_LABEL, msg, KiBitmap( add_line_label_xpm ) ); + + // Add global label command only if the cursor is over one end of the wire. + if( Wire->IsEndPoint( pos ) ) + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_GLABEL, _( "Add Global Label" ), + KiBitmap( add_glabel_xpm ) ); +} + + +void AddMenusForBus( wxMenu* PopMenu, SCH_LINE* Bus, SCH_EDIT_FRAME* frame ) +{ + wxPoint pos = frame->GetCrossHairPosition(); + wxString msg; + + if( Bus == NULL ) + { + msg = AddHotkeyName( _( "Begin Bus" ), g_Schematic_Hokeys_Descr, HK_BEGIN_BUS ); + AddMenuItem( PopMenu, ID_POPUP_SCH_BEGIN_BUS, msg, KiBitmap( add_bus_xpm ) ); + return; + } + + bool is_new = Bus->IsNew(); + if( is_new ) + { + msg = AddHotkeyName( _( "Bus End" ), g_Schematic_Hokeys_Descr, HK_END_CURR_LINEWIREBUS ); + AddMenuItem( PopMenu, ID_POPUP_END_LINE, msg, KiBitmap( checked_ok_xpm ) ); + return; + } + + msg = AddHotkeyName( _( "Delete Bus" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_bus_xpm ) ); + + AddMenuItem( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Bus" ), KiBitmap( break_bus_xpm ) ); + + PopMenu->AppendSeparator(); + msg = AddHotkeyName( _( "Add Junction" ), g_Schematic_Hokeys_Descr, HK_ADD_JUNCTION ); + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_JUNCTION, msg, KiBitmap( add_junction_xpm ) ); + msg = AddHotkeyName( _( "Add Label" ), g_Schematic_Hokeys_Descr, HK_ADD_LABEL ); + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_LABEL, msg, KiBitmap( add_line_label_xpm ) ); + + // Add global label command only if the cursor is over one end of the bus. + if( Bus->IsEndPoint( pos ) ) + AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_GLABEL, _( "Add Global Label" ), + KiBitmap( add_glabel_xpm ) ); +} + + +void AddMenusForHierchicalSheet( wxMenu* PopMenu, SCH_SHEET* Sheet ) +{ + wxString msg; + + if( !Sheet->GetFlags() ) + { + AddMenuItem( PopMenu, ID_POPUP_SCH_ENTER_SHEET, _( "Enter Sheet" ), + KiBitmap( enter_sheet_xpm ) ); + PopMenu->AppendSeparator(); + msg = AddHotkeyName( _( "Move Sheet" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_sheet_xpm ) ); + + msg = AddHotkeyName( _( "Drag Sheet" ), g_Schematic_Hokeys_Descr, HK_DRAG ); + AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_sheet_xpm ) ); + + wxMenu* orientmenu = new wxMenu; + msg = AddHotkeyName( _( "Rotate Sheet CW" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( orientmenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_cw_xpm ) ); + + AddMenuItem( orientmenu, ID_SCH_ROTATE_COUNTERCLOCKWISE, _( "Rotate Sheet CCW" ), + KiBitmap( rotate_ccw_xpm ) ); + + msg = AddHotkeyName( _( "Mirror --" ), g_Schematic_Hokeys_Descr, HK_MIRROR_X ); + AddMenuItem( orientmenu, ID_SCH_MIRROR_X, msg, KiBitmap( mirror_v_xpm ) ); + msg = AddHotkeyName( _( "Mirror ||" ), g_Schematic_Hokeys_Descr, HK_MIRROR_Y ); + AddMenuItem( orientmenu, ID_SCH_MIRROR_Y, msg, KiBitmap( mirror_h_xpm ) ); + + AddMenuItem( PopMenu, orientmenu, ID_POPUP_SCH_GENERIC_ORIENT_CMP, + _( "Orient Sheet" ), KiBitmap( orient_xpm ) ); + } + + if( Sheet->GetFlags() ) + { + AddMenuItem( PopMenu, ID_POPUP_SCH_END_SHEET, _( "Place Sheet" ), KiBitmap( checked_ok_xpm ) ); + } + else + { + msg = AddHotkeyName( _( "Edit Sheet" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_sheet_xpm ) ); + + AddMenuItem( PopMenu, ID_POPUP_SCH_RESIZE_SHEET, _( "Resize Sheet" ), + KiBitmap( resize_sheet_xpm ) ); + PopMenu->AppendSeparator(); + AddMenuItem( PopMenu, ID_POPUP_IMPORT_HLABEL_TO_SHEETPIN, _( "Import Sheet Pins" ), + KiBitmap( import_hierarchical_label_xpm ) ); + + if( Sheet->HasUndefinedPins() ) // Sheet has pin labels, and can be cleaned + AddMenuItem( PopMenu, ID_POPUP_SCH_CLEANUP_SHEET, _( "Cleanup Sheet Pins" ), + KiBitmap( options_pinsheet_xpm ) ); + + PopMenu->AppendSeparator(); + msg = AddHotkeyName( _( "Delete Sheet" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_sheet_xpm ) ); + } +} + + +void AddMenusForSheetPin( wxMenu* PopMenu, SCH_SHEET_PIN* PinSheet ) +{ + wxString msg; + + if( !PinSheet->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Sheet Pin" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( PopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_xpm ) ); + } + + AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, _( "Edit Sheet Pin" ), KiBitmap( edit_xpm ) ); + + if( !PinSheet->GetFlags() ) + AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, _( "Delete Sheet Pin" ), + KiBitmap( delete_pinsheet_xpm ) ); +} + + +void AddMenusForBlock( wxMenu* PopMenu, SCH_EDIT_FRAME* frame ) +{ + wxString msg; + + AddMenuItem( PopMenu, ID_POPUP_CANCEL_CURRENT_COMMAND, _( "Cancel Block" ), + KiBitmap( cancel_xpm ) ); + + PopMenu->AppendSeparator(); + + if( frame->GetScreen()->m_BlockLocate.GetCommand() == BLOCK_MOVE ) + AddMenuItem( PopMenu, ID_POPUP_ZOOM_BLOCK, _( "Window Zoom" ), KiBitmap( zoom_area_xpm ) ); + + AddMenuItem( PopMenu, ID_POPUP_PLACE_BLOCK, _( "Place Block" ), KiBitmap( checked_ok_xpm ) ); + + // After a block move (that is also a block selection) one can reselect + // a block function. + if( frame->GetScreen()->m_BlockLocate.GetCommand() == BLOCK_MOVE ) + { + msg = AddHotkeyName( _( "Save Block" ), g_Schematic_Hokeys_Descr, + HK_SAVE_BLOCK ); + AddMenuItem( PopMenu, wxID_COPY, msg, KiBitmap( copy_button_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_COPY_BLOCK, _( "Copy Block" ), KiBitmap( copyblock_xpm ) ); + msg = AddHotkeyName( _( "Drag Block" ), g_Schematic_Hokeys_Descr, + HK_MOVEBLOCK_TO_DRAGBLOCK ); + AddMenuItem( PopMenu, ID_POPUP_DRAG_BLOCK, msg, KiBitmap( move_xpm ) ); + AddMenuItem( PopMenu, ID_POPUP_DELETE_BLOCK, _( "Delete Block" ), KiBitmap( delete_xpm ) ); + msg = AddHotkeyName( _( "Mirror Block ||" ), g_Schematic_Hokeys_Descr, + HK_MIRROR_Y ); + AddMenuItem( PopMenu, ID_SCH_MIRROR_Y, msg, KiBitmap( mirror_h_xpm ) ); + msg = AddHotkeyName( _( "Mirror Block --" ), g_Schematic_Hokeys_Descr, + HK_MIRROR_X ); + AddMenuItem( PopMenu, ID_SCH_MIRROR_X, msg, KiBitmap( mirror_v_xpm ) ); + msg = AddHotkeyName( _( "Rotate Block CCW" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( PopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_ccw_xpm ) ); + +#if 0 + #ifdef __WINDOWS__ + AddMenuItem( menu_other_block_commands, ID_GEN_COPY_BLOCK_TO_CLIPBOARD, + _( "Copy to Clipboard" ), KiBitmap( copy_button_xpm ) ); + #endif +#endif + } +} + + +void AddMenusForMarkers( wxMenu* aPopMenu, SCH_MARKER* aMarker, SCH_EDIT_FRAME* aFrame ) +{ + AddMenuItem( aPopMenu, ID_POPUP_SCH_DELETE, _( "Delete Marker" ), KiBitmap( delete_xpm ) ); + AddMenuItem( aPopMenu, ID_POPUP_SCH_GETINFO_MARKER, _( "Marker Error Info" ), + KiBitmap( info_xpm ) ); +} + + +void AddMenusForBitmap( wxMenu* aPopMenu, SCH_BITMAP * aBitmap ) +{ + wxString msg; + + if( aBitmap->GetFlags() == 0 ) + { + msg = AddHotkeyName( _( "Move Image" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( aPopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_xpm ) ); + } + + msg = AddHotkeyName( _( "Rotate Image" ), g_Schematic_Hokeys_Descr, HK_ROTATE ); + AddMenuItem( aPopMenu, ID_SCH_ROTATE_CLOCKWISE, msg, KiBitmap( rotate_ccw_xpm ) ); + msg = AddHotkeyName( _( "Mirror --" ), g_Schematic_Hokeys_Descr, + HK_MIRROR_X ); + AddMenuItem( aPopMenu, ID_SCH_MIRROR_X, msg, KiBitmap( mirror_v_xpm ) ); + msg = AddHotkeyName( _( "Mirror ||" ), g_Schematic_Hokeys_Descr, + HK_MIRROR_Y ); + AddMenuItem( aPopMenu, ID_SCH_MIRROR_Y, msg, KiBitmap( mirror_h_xpm ) ); + msg = AddHotkeyName( _( "Edit Image" ), g_Schematic_Hokeys_Descr, HK_EDIT ); + AddMenuItem( aPopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( image_xpm ) ); + + if( aBitmap->GetFlags() == 0 ) + { + aPopMenu->AppendSeparator(); + msg = AddHotkeyName( _( "Delete Image" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( aPopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_xpm ) ); + } +} + + +void AddMenusForBusEntry( wxMenu* aPopMenu, SCH_BUS_ENTRY_BASE* aBusEntry ) +{ + wxString msg; + + if( !aBusEntry->GetFlags() ) + { + msg = AddHotkeyName( _( "Move Bus Entry" ), g_Schematic_Hokeys_Descr, + HK_MOVE_COMPONENT_OR_ITEM ); + AddMenuItem( aPopMenu, ID_SCH_MOVE_ITEM, msg, KiBitmap( move_xpm ) ); + } + + if( aBusEntry->GetBusEntryShape() == '\\' ) + AddMenuItem( aPopMenu, ID_POPUP_SCH_ENTRY_SELECT_SLASH, + _( "Set Bus Entry Shape /" ), KiBitmap( change_entry_orient_xpm ) ); + else + AddMenuItem( aPopMenu, ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH, + _( "Set Bus Entry Shape \\" ), KiBitmap( change_entry_orient_xpm ) ); + + msg = AddHotkeyName( _( "Delete Bus Entry" ), g_Schematic_Hokeys_Descr, HK_DELETE ); + AddMenuItem( aPopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_xpm ) ); +} diff --git a/eeschema/operations_on_items_lists.cpp b/eeschema/operations_on_items_lists.cpp new file mode 100644 index 00000000..89346b19 --- /dev/null +++ b/eeschema/operations_on_items_lists.cpp @@ -0,0 +1,264 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 + */ + +/** + * @file operations_on_items_lists.cpp + * @brief Functions used in block commands, or undo/redo, to move, mirror, delete, copy ... + * lists of schematic items. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void SetSchItemParent( SCH_ITEM* Struct, SCH_SCREEN* Screen ) +{ + switch( Struct->Type() ) + { + case SCH_JUNCTION_T: + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_COMPONENT_T: + case SCH_LINE_T: + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + case SCH_SHEET_T: + case SCH_MARKER_T: + case SCH_NO_CONNECT_T: + Struct->SetParent( Screen ); + break; + + case SCH_SHEET_PIN_T: + break; + + default: + break; + } +} + + +void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, wxPoint& rotationPoint ) +{ + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + item->Rotate( rotationPoint ); // Place it in its new position. + item->ClearFlags(); + } +} + + +void MirrorY( PICKED_ITEMS_LIST& aItemsList, wxPoint& aMirrorPoint ) +{ + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + item->MirrorY( aMirrorPoint.x ); // Place it in its new position. + item->ClearFlags(); + } +} + + +void MirrorX( PICKED_ITEMS_LIST& aItemsList, wxPoint& aMirrorPoint ) +{ + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + item->MirrorX( aMirrorPoint.y ); // Place it in its new position. + item->ClearFlags(); + } +} + + +/** + * Function MoveItemsInList + * Move a list of items to a given move vector + * @param aItemsList = list of picked items + * @param aMoveVector = the move vector value + */ +void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint aMoveVector ) +{ + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + item->Move( aMoveVector ); + } +} + + +/** + * Function DeleteItemsInList + * delete schematic items in aItemsList + * deleted items are put in undo list + */ +void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) panel->GetScreen(); + SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) panel->GetParent(); + PICKED_ITEMS_LIST itemsList; + + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + ITEM_PICKER itemWrapper( item, UR_DELETED ); + + if( item->Type() == SCH_SHEET_PIN_T ) + { + /* this item is depending on a sheet, and is not in global list */ + wxMessageBox( wxT( "DeleteItemsInList() err: unexpected SCH_SHEET_PIN_T" ) ); + } + else + { + screen->Remove( item ); + + /* Unlink the structure */ + itemsList.PushItem( itemWrapper ); + } + } + + frame->SaveCopyInUndoList( itemsList, UR_DELETED ); +} + + +void SCH_EDIT_FRAME::DeleteItem( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem != NULL, wxT( "Cannot delete invalid item." ) ); + + // Here, aItem is not null. + + SCH_SCREEN* screen = GetScreen(); + + if( aItem->Type() == SCH_SHEET_PIN_T ) + { + // This iten is attached to a node, and is not accessible by the global list directly. + SCH_SHEET* sheet = (SCH_SHEET*) aItem->GetParent(); + wxCHECK_RET( (sheet != NULL) && (sheet->Type() == SCH_SHEET_T), + wxT( "Sheet label has invalid parent item." ) ); + SaveCopyInUndoList( (SCH_ITEM*) sheet, UR_CHANGED ); + sheet->RemovePin( (SCH_SHEET_PIN*) aItem ); + m_canvas->RefreshDrawingRect( sheet->GetBoundingBox() ); + } + else + { + screen->Remove( aItem ); + SaveCopyInUndoList( aItem, UR_DELETED ); + m_canvas->RefreshDrawingRect( aItem->GetBoundingBox() ); + } +} + + +/* Routine to copy a new entity of an object for each object in list and + * reposition it. + * Return the new created object list in aItemsList + */ +void DuplicateItemsInList( SCH_SCREEN* screen, PICKED_ITEMS_LIST& aItemsList, + const wxPoint aMoveVector ) +{ + SCH_ITEM* newitem; + + if( aItemsList.GetCount() == 0 ) + return; + + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + { + newitem = DuplicateStruct( (SCH_ITEM*) aItemsList.GetPickedItem( ii ) ); + aItemsList.SetPickedItem( newitem, ii ); + aItemsList.SetPickedItemStatus( UR_NEW, ii ); + { + switch( newitem->Type() ) + { + case SCH_JUNCTION_T: + case SCH_LINE_T: + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_SHEET_PIN_T: + case SCH_MARKER_T: + case SCH_NO_CONNECT_T: + default: + break; + + case SCH_SHEET_T: + { + SCH_SHEET* sheet = (SCH_SHEET*) newitem; + sheet->SetTimeStamp( GetNewTimeStamp() ); + break; + } + + case SCH_COMPONENT_T: + ( (SCH_COMPONENT*) newitem )->SetTimeStamp( GetNewTimeStamp() ); + ( (SCH_COMPONENT*) newitem )->ClearAnnotation( NULL ); + break; + } + + SetSchItemParent( newitem, screen ); + screen->Append( newitem ); + } + } + + MoveItemsInList( aItemsList, aMoveVector ); +} + + +/** + * Function DuplicateStruct + * Routine to create a new copy of given struct. + * The new object is not put in draw list (not linked) + * @param aDrawStruct = the SCH_ITEM to duplicate + * @param aClone (default = false) + * if true duplicate also some parameters that must be unique + * (timestamp and sheet name) + * aClone must be false. use true only is undo/redo duplications + */ +SCH_ITEM* DuplicateStruct( SCH_ITEM* aDrawStruct, bool aClone ) +{ + wxCHECK_MSG( aDrawStruct != NULL, NULL, + wxT( "Cannot duplicate NULL schematic item! Bad programmer." ) ); + + SCH_ITEM* NewDrawStruct = (SCH_ITEM*) aDrawStruct->Clone(); + + if( aClone ) + NewDrawStruct->SetTimeStamp( aDrawStruct->GetTimeStamp() ); + + NewDrawStruct->SetImage( aDrawStruct ); + + return NewDrawStruct; +} diff --git a/eeschema/pinedit.cpp b/eeschema/pinedit.cpp new file mode 100644 index 00000000..1b44172f --- /dev/null +++ b/eeschema/pinedit.cpp @@ -0,0 +1,786 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file pinedit.cpp + * @brief Eeschema pin edit code. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include <../common/dialogs/dialog_display_info_HTML_base.h> +#include + + +extern void IncrementLabelMember( wxString& name, int aIncrement ); + + +static void AbortPinMove( EDA_DRAW_PANEL* Panel, wxDC* DC ); +static void DrawMovePin( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPositon, bool aErase ); + + +static wxPoint OldPos; +static wxPoint PinPreviousPos; +static int LastPinType = PIN_INPUT; +static int LastPinOrient = PIN_RIGHT; +static int LastPinShape = NONE; +static bool LastPinCommonConvert = false; +static bool LastPinCommonUnit = false; +static bool LastPinVisible = true; + +// The -1 is a non-valid value to trigger delayed initialization +static int LastPinLength = -1; +static int LastPinNameSize = -1; +static int LastPinNumSize = -1; + +static int GetLastPinLength() +{ + if( LastPinLength == -1 ) + LastPinLength = LIB_EDIT_FRAME::GetDefaultPinLength(); + + return LastPinLength; +} + +static int GetLastPinNameSize() +{ + if( LastPinNameSize == -1 ) + LastPinNameSize = LIB_EDIT_FRAME::GetPinNameDefaultSize(); + + return LastPinNameSize; +} + +static int GetLastPinNumSize() +{ + if( LastPinNumSize == -1 ) + LastPinNumSize = LIB_EDIT_FRAME::GetPinNumDefaultSize(); + + return LastPinNumSize; +} + +void LIB_EDIT_FRAME::OnEditPin( wxCommandEvent& event ) +{ + if( m_drawItem == NULL || m_drawItem->Type() != LIB_PIN_T ) + return; + + STATUS_FLAGS item_flags = m_drawItem->GetFlags(); // save flags to restore them after editing + LIB_PIN* pin = (LIB_PIN*) m_drawItem; + + DIALOG_LIB_EDIT_PIN dlg( this, pin ); + + wxString units = GetUnitsLabel( g_UserUnit ); + dlg.SetOrientationList( LIB_PIN::GetOrientationNames(), LIB_PIN::GetOrientationSymbols() ); + dlg.SetOrientation( LIB_PIN::GetOrientationCodeIndex( pin->GetOrientation() ) ); + dlg.SetStyleList( LIB_PIN::GetStyleNames(), LIB_PIN::GetStyleSymbols() ); + dlg.SetStyle( LIB_PIN::GetStyleCodeIndex( pin->GetShape() ) ); + dlg.SetElectricalTypeList( LIB_PIN::GetElectricalTypeNames(), + LIB_PIN::GetElectricalTypeSymbols() ); + dlg.SetElectricalType( pin->GetType() ); + dlg.SetPinName( pin->GetName() ); + dlg.SetPinNameTextSize( StringFromValue( g_UserUnit, pin->GetNameTextSize() ) ); + dlg.SetPinNameTextSizeUnits( units ); + dlg.SetPadName( pin->GetNumberString() ); + dlg.SetPadNameTextSize( StringFromValue( g_UserUnit, pin->GetNumberTextSize() ) ); + + dlg.SetPadNameTextSizeUnits( units ); + dlg.SetLength( StringFromValue( g_UserUnit, pin->GetLength() ) ); + dlg.SetLengthUnits( units ); + dlg.SetAddToAllParts( pin->GetUnit() == 0 ); + dlg.SetAddToAllBodyStyles( pin->GetConvert() == 0 ); + dlg.SetVisible( pin->IsVisible() ); + + /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier + * versions for the flex grid sizer in wxGTK that prevents the last + * column from being sized correctly. It doesn't cause any problems + * on win32 so it doesn't need to wrapped in ugly #ifdef __WXGTK__ + * #endif. + */ + dlg.Layout(); + dlg.Fit(); + dlg.SetMinSize( dlg.GetSize() ); + + if( dlg.ShowModal() == wxID_CANCEL ) + { + if( pin->IsNew() ) + { + pin->SetFlags( IS_CANCELLED ); + m_canvas->EndMouseCapture(); + } + return; + } + + // Save the pin properties to use for the next new pin. + LastPinNameSize = ValueFromString( g_UserUnit, dlg.GetPinNameTextSize() ); + LastPinNumSize = ValueFromString( g_UserUnit, dlg.GetPadNameTextSize() ); + LastPinOrient = LIB_PIN::GetOrientationCode( dlg.GetOrientation() ); + LastPinLength = ValueFromString( g_UserUnit, dlg.GetLength() ); + LastPinShape = LIB_PIN::GetStyleCode( dlg.GetStyle() ); + LastPinType = dlg.GetElectricalType(); + LastPinCommonConvert = dlg.GetAddToAllBodyStyles(); + LastPinCommonUnit = dlg.GetAddToAllParts(); + LastPinVisible = dlg.GetVisible(); + + pin->EnableEditMode( true, m_editPinsPerPartOrConvert ); + pin->SetName( dlg.GetPinName() ); + pin->SetNameTextSize( GetLastPinNameSize() ); + pin->SetNumber( dlg.GetPadName() ); + pin->SetNumberTextSize( GetLastPinNumSize() ); + pin->SetOrientation( LastPinOrient ); + pin->SetLength( GetLastPinLength() ); + pin->SetType( LastPinType ); + pin->SetShape( LastPinShape ); + pin->SetConversion( ( LastPinCommonConvert ) ? 0 : m_convert ); + pin->SetPartNumber( ( LastPinCommonUnit ) ? 0 : m_unit ); + pin->SetVisible( LastPinVisible ); + + if( pin->IsModified() || pin->IsNew() ) + { + if( !pin->InEditMode() ) + SaveCopyInUndoList( pin->GetParent() ); + + OnModify( ); + + MSG_PANEL_ITEMS items; + pin->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + m_canvas->Refresh(); + } + + pin->EnableEditMode( false, m_editPinsPerPartOrConvert ); + + // Restore pin flags, that can be changed by the dialog editor + pin->ClearFlags(); + pin->SetFlags( item_flags ); +} + +/** + * Clean up after aborting a move pin command. + */ +static void AbortPinMove( EDA_DRAW_PANEL* Panel, wxDC* DC ) +{ + LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) Panel->GetParent(); + + if( parent == NULL ) + return; + + LIB_PIN* pin = (LIB_PIN*) parent->GetDrawItem(); + + if( pin == NULL || pin->Type() != LIB_PIN_T ) + return; + + pin->ClearFlags(); + + if( pin->IsNew() ) + delete pin; + else + parent->RestoreComponent(); + + // clear edit flags + parent->SetDrawItem( NULL ); + parent->SetLastDrawItem( NULL ); + Panel->Refresh( true ); +} + + +/** + * Managed cursor callback for placing component pins. + */ +void LIB_EDIT_FRAME::PlacePin() +{ + LIB_PIN* cur_pin = (LIB_PIN*) m_drawItem; + bool ask_for_pin = true; + wxPoint newpos; + bool status; + + // Some tests + if( !cur_pin || cur_pin->Type() != LIB_PIN_T ) + { + wxMessageBox( wxT( "LIB_EDIT_FRAME::PlacePin() error" ) ); + return; + } + + newpos = GetCrossHairPosition( true ); + + LIB_PART* part = GetCurPart(); + + // Test for an other pin in same new position: + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + if( pin == cur_pin || newpos != pin->GetPosition() || pin->GetFlags() ) + continue; + + if( ask_for_pin && SynchronizePins() ) + { + m_canvas->SetIgnoreMouseEvents( true ); + + status = IsOK( this, _( "This position is already occupied by another pin. Continue?" ) ); + + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + + if( !status ) + return; + else + ask_for_pin = false; + } + } + + // Create Undo from GetTempCopyComponent() if exists ( i.e. after a pin move) + // or from m_component (pin add ...) + if( GetTempCopyComponent() ) + SaveCopyInUndoList( GetTempCopyComponent() ); + else + SaveCopyInUndoList( part ); + + m_canvas->SetMouseCapture( NULL, NULL ); + OnModify(); + cur_pin->Move( newpos ); + + if( cur_pin->IsNew() ) + { + LastPinOrient = cur_pin->GetOrientation(); + LastPinType = cur_pin->GetType(); + LastPinShape = cur_pin->GetShape(); + + if( SynchronizePins() ) + CreateImagePins( cur_pin, m_unit, m_convert, m_showDeMorgan ); + + m_lastDrawItem = cur_pin; + part->AddDrawItem( m_drawItem ); + } + + // Put linked pins in new position, and clear flags + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + if( pin->GetFlags() == 0 ) + continue; + + pin->Move( cur_pin->GetPosition() ); + pin->ClearFlags(); + } + + m_drawItem = NULL; + + m_canvas->Refresh(); +} + + +/** + * Prepare the displacement of a pin + * + * Locate the pin pointed to by the cursor, and set the cursor management + * function move the pin. + */ +void LIB_EDIT_FRAME::StartMovePin( wxDC* DC ) +{ + LIB_PIN* cur_pin = (LIB_PIN*) m_drawItem; + wxPoint startPos; + + TempCopyComponent(); + + LIB_PART* part = GetCurPart(); + + // Mark pins for moving. + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + pin->ClearFlags(); + + if( pin == cur_pin ) + continue; + + if( pin->GetPosition() == cur_pin->GetPosition() && + pin->GetOrientation() == cur_pin->GetOrientation() && SynchronizePins() ) + { + pin->SetFlags( IS_LINKED | IS_MOVED ); + } + } + + cur_pin->SetFlags( IS_LINKED | IS_MOVED ); + + PinPreviousPos = OldPos = cur_pin->GetPosition(); + startPos.x = OldPos.x; + startPos.y = -OldPos.y; + +// m_canvas->CrossHairOff( DC ); + SetCrossHairPosition( startPos ); + m_canvas->MoveCursorToCrossHair(); + + MSG_PANEL_ITEMS items; + + cur_pin->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + m_canvas->SetMouseCapture( DrawMovePin, AbortPinMove ); +// m_canvas->CrossHairOn( DC ); + + // Refresh the screen to avoid color artifacts when drawing + // the pin in Edit mode and moving it from its start position + m_canvas->Refresh(); +} + + +/* Move pin to the current mouse position. This function is called by the + * cursor management code. */ +static void DrawMovePin( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) aPanel->GetParent(); + + if( parent == NULL ) + return; + + LIB_PIN* cur_pin = (LIB_PIN*) parent->GetDrawItem(); + + if( cur_pin == NULL || cur_pin->Type() != LIB_PIN_T ) + return; + + wxPoint pinpos = cur_pin->GetPosition(); + bool showPinText = true; + + // Erase pin in old position + if( aErase ) + { + cur_pin->Move( PinPreviousPos ); + cur_pin->Draw( aPanel, aDC, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, g_XorMode, + &showPinText, DefaultTransform ); + } + + // Redraw pin in new position + cur_pin->Move( aPanel->GetParent()->GetCrossHairPosition( true ) ); + cur_pin->Draw( aPanel, aDC, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, g_XorMode, + &showPinText, DefaultTransform ); + + PinPreviousPos = cur_pin->GetPosition(); + + /* Keep the original position for existing pin (for Undo command) + * and the current position for a new pin */ + if( !cur_pin->IsNew() ) + cur_pin->Move( pinpos ); +} + + +/* + * Create a new pin. + */ +void LIB_EDIT_FRAME::CreatePin( wxDC* DC ) +{ + bool showPinText = true; + + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + part->ClearStatus(); + + LIB_PIN* pin = new LIB_PIN( part ); + + m_drawItem = pin; + + pin->SetFlags( IS_NEW ); + pin->SetUnit( m_unit ); + pin->SetConvert( m_convert ); + + // Flag pins to consider + if( SynchronizePins() ) + pin->SetFlags( IS_LINKED ); + + pin->Move( GetCrossHairPosition( true ) ); + pin->SetLength( GetLastPinLength() ); + pin->SetOrientation( LastPinOrient ); + pin->SetType( LastPinType ); + pin->SetShape( LastPinShape ); + pin->SetNameTextSize( GetLastPinNameSize() ); + pin->SetNumberTextSize( GetLastPinNumSize() ); + pin->SetConvert( LastPinCommonConvert ? 0 : m_convert ); + pin->SetUnit( LastPinCommonUnit ? 0 : m_unit ); + pin->SetVisible( LastPinVisible ); + PinPreviousPos = pin->GetPosition(); + m_canvas->SetIgnoreMouseEvents( true ); + wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); + cmd.SetId( ID_LIBEDIT_EDIT_PIN ); + GetEventHandler()->ProcessEvent( cmd ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + + if( pin->GetFlags() & IS_CANCELLED ) + { + deleteItem( DC ); + } + else + { + ClearTempCopyComponent(); + m_canvas->SetMouseCapture( DrawMovePin, AbortPinMove ); + + if( DC ) + pin->Draw( m_canvas, DC, wxPoint( 0, 0 ), UNSPECIFIED_COLOR, GR_COPY, &showPinText, + DefaultTransform ); + + } +} + + +void LIB_EDIT_FRAME::CreateImagePins( LIB_PIN* aPin, int aUnit, int aConvert, bool aDeMorgan ) +{ + int ii; + LIB_PIN* NewPin; + + if( !SynchronizePins() ) + return; + + // Create "convert" pin at the current position. + if( aDeMorgan && ( aPin->GetConvert() != 0 ) ) + { + NewPin = (LIB_PIN*) aPin->Clone(); + + if( aPin->GetConvert() > 1 ) + NewPin->SetConvert( 1 ); + else + NewPin->SetConvert( 2 ); + + aPin->GetParent()->AddDrawItem( NewPin ); + } + + for( ii = 1; ii <= aPin->GetParent()->GetUnitCount(); ii++ ) + { + if( ii == aUnit || aPin->GetUnit() == 0 ) + continue; // Pin common to all units. + + NewPin = (LIB_PIN*) aPin->Clone(); + + // To avoid mistakes, gives this pin a new pin number because + // it does no have the save pin number as the master pin + // Because we do not know the actual number, give it '??' + wxString unknownNum( wxT( "??" ) ); + NewPin->SetPinNumFromString( unknownNum ); + + if( aConvert != 0 ) + NewPin->SetConvert( 1 ); + + NewPin->SetUnit( ii ); + aPin->GetParent()->AddDrawItem( NewPin ); + + if( !( aDeMorgan && ( aPin->GetConvert() != 0 ) ) ) + continue; + + NewPin = (LIB_PIN*) aPin->Clone(); + NewPin->SetConvert( 2 ); + // Gives this pin a new pin number + // Because we do not know the actual number, give it '??' + NewPin->SetPinNumFromString( unknownNum ); + + if( aPin->GetUnit() != 0 ) + NewPin->SetUnit( ii ); + + aPin->GetParent()->AddDrawItem( NewPin ); + } +} + + +/* aMasterPin is the "template" pin + * aId is a param to select what should be mofified: + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM: + * Change pins text name size + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM: + * Change pins text num size + * - aId = ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM: + * Change pins length. + * + * If aMasterPin is selected ( .m_flag == IS_SELECTED ), + * only the other selected pins are modified + */ +void LIB_EDIT_FRAME::GlobalSetPins( LIB_PIN* aMasterPin, int aId ) + +{ + LIB_PART* part = GetCurPart(); + + if( !part || !aMasterPin ) + return; + + if( aMasterPin->Type() != LIB_PIN_T ) + return; + + OnModify( ); + + bool selected = aMasterPin->IsSelected(); + + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + if( pin->GetConvert() && pin->GetConvert() != m_convert ) + continue; + + // Is it the "selected mode" ? + if( selected && !pin->IsSelected() ) + continue; + + switch( aId ) + { + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM: + pin->SetNumberTextSize( aMasterPin->GetNumberTextSize() ); + break; + + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM: + pin->SetNameTextSize( aMasterPin->GetNameTextSize() ); + break; + + case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM: + pin->SetLength( aMasterPin->GetLength() ); + break; + } + + // Clear the flag IS_CHANGED, which was set by previous changes (if any) + // but not used here. + pin->ClearFlags( IS_CHANGED ); + } +} + + +// Create a new pin based on the previous pin with an incremented pin number. +void LIB_EDIT_FRAME::RepeatPinItem( wxDC* DC, LIB_PIN* SourcePin ) +{ + wxString msg; + + LIB_PART* part = GetCurPart(); + + if( !part || !SourcePin || SourcePin->Type() != LIB_PIN_T ) + return; + + LIB_PIN* pin = (LIB_PIN*) SourcePin->Clone(); + + pin->ClearFlags(); + pin->SetFlags( IS_NEW ); + wxPoint step; + + switch( pin->GetOrientation() ) + { + case PIN_UP: + step.x = GetRepeatPinStep(); + break; + + case PIN_DOWN: + step.x = GetRepeatPinStep(); + break; + + case PIN_LEFT: + step.y = - GetRepeatPinStep(); + break; + + case PIN_RIGHT: + step.y = - GetRepeatPinStep(); + break; + } + + pin->Move( pin->GetPosition() + step ); + wxString nextName = pin->GetName(); + IncrementLabelMember( nextName, GetRepeatDeltaLabel() ); + pin->SetName( nextName ); + + pin->PinStringNum( msg ); + IncrementLabelMember( msg, GetRepeatDeltaLabel() ); + pin->SetPinNumFromString( msg ); + + m_drawItem = pin; + + if( SynchronizePins() ) + pin->SetFlags( IS_LINKED ); + + wxPoint savepos = GetCrossHairPosition(); + m_canvas->CrossHairOff( DC ); + + SetCrossHairPosition( wxPoint( pin->GetPosition().x, -pin->GetPosition().y ) ); + + // Add this new pin in list, and creates pins for others parts if needed + m_drawItem = pin; + ClearTempCopyComponent(); + PlacePin(); + m_lastDrawItem = pin; + + SetCrossHairPosition( savepos ); + m_canvas->CrossHairOn( DC ); + + MSG_PANEL_ITEMS items; + pin->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + OnModify( ); +} + + +// helper function to sort pins by pin num +bool sort_by_pin_number( const LIB_PIN* ref, const LIB_PIN* tst ) +{ + int test = ref->GetNumber() - tst->GetNumber(); + + if( test == 0 ) + { + test = ref->GetConvert() - tst->GetConvert(); + } + + if( test == 0 ) + { + test = ref->GetUnit() - tst->GetUnit(); + } + + return test < 0; +} + + +void LIB_EDIT_FRAME::OnCheckComponent( wxCommandEvent& event ) +{ + LIB_PART* part = GetCurPart(); + + if( !part ) + return; + + const int MIN_GRID_SIZE = 25; + + LIB_PINS pinList; + + part->GetPins( pinList ); + + if( pinList.size() == 0 ) + { + DisplayInfoMessage( this, _( "No pins!" ) ); + return; + } + + // Sort pins by pin num, so 2 duplicate pins + // (pins with the same number) will be consecutive in list + sort( pinList.begin(), pinList.end(), sort_by_pin_number ); + + // Test for duplicates: + DIALOG_DISPLAY_HTML_TEXT_BASE error_display( this, wxID_ANY, + _( "Marker Information" ), + wxDefaultPosition, + wxSize( 750, 600 ) ); + + int dup_error = 0; + + for( unsigned ii = 1; ii < pinList.size(); ii++ ) + { + wxString stringPinNum, stringCurrPinNum; + + LIB_PIN* curr_pin = pinList[ii]; + LIB_PIN* pin = pinList[ii - 1]; + + if( pin->GetNumber() != curr_pin->GetNumber() + || pin->GetConvert() != curr_pin->GetConvert() + || pin->GetUnit() != curr_pin->GetUnit() ) + continue; + + dup_error++; + pin->PinStringNum( stringPinNum ); + + /* TODO I dare someone to find a way to make happy translators on + this thing! Lorenzo */ + curr_pin->PinStringNum( stringCurrPinNum ); + + wxString msg = wxString::Format( _( + "Duplicate pin %s \"%s\" at location (%.3f, %.3f)" + " conflicts with pin %s \"%s\" at location (%.3f, %.3f)" ), + GetChars( stringCurrPinNum ), + GetChars( curr_pin->GetName() ), + curr_pin->GetPosition().x / 1000.0, + -curr_pin->GetPosition().y / 1000.0, + GetChars( stringPinNum ), + GetChars( pin->GetName() ), + pin->GetPosition().x / 1000.0, + -pin->GetPosition().y / 1000.0 + ); + + if( part->GetUnitCount() > 1 ) + { + msg += wxString::Format( _( " in part %c" ), 'A' + curr_pin->GetUnit() - 1 ); + } + + if( m_showDeMorgan ) + { + if( curr_pin->GetConvert() ) + msg += _( " of converted" ); + else + msg += _( " of normal" ); + } + + msg += wxT( ".
      " ); + + error_display.m_htmlWindow->AppendToPage( msg ); + } + + // Test for off grid pins: + int offgrid_error = 0; + + for( unsigned ii = 0; ii < pinList.size(); ii++ ) + { + LIB_PIN* pin = pinList[ii]; + + if( ( (pin->GetPosition().x % MIN_GRID_SIZE) == 0 ) && + ( (pin->GetPosition().y % MIN_GRID_SIZE) == 0 ) ) + continue; + + // "pin" is off grid here. + offgrid_error++; + wxString stringPinNum; + pin->PinStringNum( stringPinNum ); + + wxString msg = wxString::Format( _( + "Off grid pin %s \"%s\" at location (%.3f, %.3f)" ), + GetChars( stringPinNum ), + GetChars( pin->GetName() ), + pin->GetPosition().x / 1000.0, + -pin->GetPosition().y / 1000.0 + ); + + if( part->GetUnitCount() > 1 ) + { + msg += wxString::Format( _( " in part %c" ), 'A' + pin->GetUnit() - 1 ); + } + + if( m_showDeMorgan ) + { + if( pin->GetConvert() ) + msg += _( " of converted" ); + else + msg += _( " of normal" ); + } + + msg += wxT( ".
      " ); + + error_display.m_htmlWindow->AppendToPage( msg ); + } + + if( !dup_error && !offgrid_error ) + DisplayInfoMessage( this, _( "No off grid or duplicate pins were found." ) ); + else + error_display.ShowModal(); +} diff --git a/eeschema/plot_schematic_DXF.cpp b/eeschema/plot_schematic_DXF.cpp new file mode 100644 index 00000000..a571c73b --- /dev/null +++ b/eeschema/plot_schematic_DXF.cpp @@ -0,0 +1,166 @@ +/** @file plot_schematic_DXF.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2010 Lorenzo Marcantonio + * Copyright (C) 1992-2010 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include + +#include +#include + + +void DIALOG_PLOT_SCHEMATIC::CreateDXFFile( bool aPlotAll, bool aPlotFrameRef ) +{ + SCH_EDIT_FRAME* schframe = m_parent; + SCH_SCREEN* screen = schframe->GetScreen(); + SCH_SHEET_PATH* sheetpath; + SCH_SHEET_PATH oldsheetpath = schframe->GetCurrentSheet(); + + /* When printing all pages, the printed page is not the current page. + * In complex hierarchies, we must setup references and others parameters + * in the printed SCH_SCREEN + * because in complex hierarchies a SCH_SCREEN (a schematic drawings) + * is shared between many sheets + */ + SCH_SHEET_LIST SheetList( NULL ); + + sheetpath = SheetList.GetFirst(); + SCH_SHEET_PATH list; + REPORTER& reporter = m_MessagesBox->Reporter(); + + while( true ) + { + if( aPlotAll ) + { + if( sheetpath == NULL ) + break; + + list.Clear(); + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + schframe->SetCurrentSheet( list ); + schframe->GetCurrentSheet().UpdateAllScreenReferences(); + schframe->SetSheetNumberAndCount(); + screen = schframe->GetCurrentSheet().LastScreen(); + } + else // Should not happen + { + return; + } + + sheetpath = SheetList.GetNext(); + } + + wxPoint plot_offset; + wxString msg; + + try + { + wxString fname = schframe->GetUniqueFilenameForCurrentSheet(); + wxString ext = DXF_PLOTTER::GetDefaultFileExtension(); + wxFileName plotFileName = createPlotFileName( m_outputDirectoryName, fname, + ext, &reporter ); + + if( PlotOneSheetDXF( plotFileName.GetFullPath(), screen, plot_offset, 1.0, aPlotFrameRef ) ) + { + msg.Printf( _( "Plot: '%s' OK.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + } + else // Error + { + msg.Printf( _( "Unable to create file '%s'.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + } + catch( IO_ERROR& e ) + { + msg.Printf( wxT( "DXF Plotter exception: %s"), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + schframe->SetCurrentSheet( oldsheetpath ); + schframe->GetCurrentSheet().UpdateAllScreenReferences(); + schframe->SetSheetNumberAndCount(); + return; + } + if( !aPlotAll ) + { + break; + } + } + + schframe->SetCurrentSheet( oldsheetpath ); + schframe->GetCurrentSheet().UpdateAllScreenReferences(); + schframe->SetSheetNumberAndCount(); +} + + +bool DIALOG_PLOT_SCHEMATIC::PlotOneSheetDXF( const wxString& aFileName, + SCH_SCREEN* aScreen, + wxPoint aPlotOffset, + double aScale, + bool aPlotFrameRef ) +{ + DXF_PLOTTER* plotter = new DXF_PLOTTER(); + + const PAGE_INFO& pageInfo = aScreen->GetPageSettings(); + plotter->SetPageSettings( pageInfo ); + plotter->SetColorMode( getModeColor() ); + plotter->SetViewport( aPlotOffset, IU_PER_DECIMILS, aScale, false ); + + // Init : + plotter->SetCreator( wxT( "Eeschema-DXF" ) ); + + if( ! plotter->OpenFile( aFileName ) ) + { + delete plotter; + return false; + } + + LOCALE_IO toggle; + + plotter->StartPlot(); + + if( aPlotFrameRef ) + { + PlotWorkSheet( plotter, m_parent->GetTitleBlock(), + m_parent->GetPageSettings(), + aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens, + m_parent->GetScreenDesc(), + aScreen->GetFileName() ); + } + + aScreen->Plot( plotter ); + + // finish + plotter->EndPlot(); + delete plotter; + + return true; +} diff --git a/eeschema/plot_schematic_HPGL.cpp b/eeschema/plot_schematic_HPGL.cpp new file mode 100644 index 00000000..9b64ab02 --- /dev/null +++ b/eeschema/plot_schematic_HPGL.cpp @@ -0,0 +1,260 @@ +/** @file plot_schematic_HPGL.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2010 Jean-Pierre Charras +#include +#include +#include +#include +#include +#include + +#include +#include + +enum HPGL_PAGEZ_T { + PAGE_DEFAULT = 0, + HPGL_PAGE_SIZE_A4, + HPGL_PAGE_SIZE_A3, + HPGL_PAGE_SIZE_A2, + HPGL_PAGE_SIZE_A1, + HPGL_PAGE_SIZE_A0, + HPGL_PAGE_SIZE_A, + HPGL_PAGE_SIZE_B, + HPGL_PAGE_SIZE_C, + HPGL_PAGE_SIZE_D, + HPGL_PAGE_SIZE_E, +}; + + +static const wxChar* plot_sheet_list( int aSize ) +{ + const wxChar* ret; + + switch( aSize ) + { + default: + case PAGE_DEFAULT: + ret = NULL; break; + + case HPGL_PAGE_SIZE_A4: + ret = wxT( "A4" ); break; + + case HPGL_PAGE_SIZE_A3: + ret = wxT( "A3" ); break; + + case HPGL_PAGE_SIZE_A2: + ret = wxT( "A2" ); break; + + case HPGL_PAGE_SIZE_A1: + ret = wxT( "A1" ); break; + + case HPGL_PAGE_SIZE_A0: + ret = wxT( "A0" ); break; + + case HPGL_PAGE_SIZE_A: + ret = wxT( "A" ); break; + + case HPGL_PAGE_SIZE_B: + ret = wxT( "B" ); break; + + case HPGL_PAGE_SIZE_C: + ret = wxT( "C" ); break; + + case HPGL_PAGE_SIZE_D: + ret = wxT( "D" ); break; + + case HPGL_PAGE_SIZE_E: + ret = wxT( "E" ); break; + } + + return ret; +}; + + +void DIALOG_PLOT_SCHEMATIC::SetHPGLPenWidth() +{ + m_HPGLPenSize = ValueFromTextCtrl( *m_penHPGLWidthCtrl ); + + if( m_HPGLPenSize > Millimeter2iu( 2 ) ) + m_HPGLPenSize = Millimeter2iu( 2 ); + + if( m_HPGLPenSize < Millimeter2iu( 0.01 ) ) + m_HPGLPenSize = Millimeter2iu( 0.01 ); +} + + +void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef ) +{ + SCH_SCREEN* screen = m_parent->GetScreen(); + SCH_SHEET_PATH* sheetpath; + SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); + + /* When printing all pages, the printed page is not the current page. + * In complex hierarchies, we must setup references and other parameters + * in the printed SCH_SCREEN + * because in complex hierarchies a SCH_SCREEN (a schematic drawings) + * is shared between many sheets + */ + SCH_SHEET_LIST SheetList( NULL ); + + sheetpath = SheetList.GetFirst(); + SCH_SHEET_PATH list; + REPORTER& reporter = m_MessagesBox->Reporter(); + + SetHPGLPenWidth(); + + while( true ) + { + if( aPlotAll ) + { + if( sheetpath == NULL ) + break; + + list.Clear(); + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + m_parent->SetCurrentSheet( list ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + + screen = m_parent->GetCurrentSheet().LastScreen(); + + if( !screen ) // LastScreen() may return NULL + screen = m_parent->GetScreen(); + } + else // Should not happen + return; + + sheetpath = SheetList.GetNext(); + } + + const PAGE_INFO& curPage = screen->GetPageSettings(); + + PAGE_INFO plotPage = curPage; + + // if plotting on a page size other than curPage + if( m_HPGLPaperSizeOption->GetSelection() != PAGE_DEFAULT ) + plotPage.SetType( plot_sheet_list( m_HPGLPaperSizeOption->GetSelection() ) ); + + // Calculation of conversion scales. + double plot_scale = (double) plotPage.GetWidthMils() / curPage.GetWidthMils(); + + // Calculate offsets + wxPoint plotOffset; + wxString msg; + + if( GetPlotOriginCenter() ) + { + plotOffset.x = plotPage.GetWidthIU() / 2; + plotOffset.y = -plotPage.GetHeightIU() / 2; + } + + try + { + wxString fname = m_parent->GetUniqueFilenameForCurrentSheet(); + wxString ext = HPGL_PLOTTER::GetDefaultFileExtension(); + wxFileName plotFileName = createPlotFileName( m_outputDirectoryName, fname, + ext, &reporter ); + + LOCALE_IO toggle; + + if( Plot_1_Page_HPGL( plotFileName.GetFullPath(), screen, plotPage, plotOffset, + plot_scale, aPlotFrameRef ) ) + { + msg.Printf( _( "Plot: '%s' OK.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + } + else + { + msg.Printf( _( "Unable to create file '%s'.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + + if( !aPlotAll ) + break; + } + catch( IO_ERROR& e ) + { + msg.Printf( wxT( "HPGL Plotter exception: %s"), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + + } + + m_parent->SetCurrentSheet( oldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); +} + + +bool DIALOG_PLOT_SCHEMATIC::Plot_1_Page_HPGL( const wxString& aFileName, + SCH_SCREEN* aScreen, + const PAGE_INFO& aPageInfo, + wxPoint aPlot0ffset, + double aScale, + bool aPlotFrameRef ) +{ + HPGL_PLOTTER* plotter = new HPGL_PLOTTER(); + + plotter->SetPageSettings( aPageInfo ); + plotter->SetViewport( aPlot0ffset, IU_PER_DECIMILS, aScale, false ); + + // Init : + plotter->SetCreator( wxT( "Eeschema-HPGL" ) ); + + if( ! plotter->OpenFile( aFileName ) ) + { + delete plotter; + return false; + } + + LOCALE_IO toggle; + + // Pen num and pen speed are not initialized here. + // Default HPGL driver values are used + plotter->SetPenDiameter( m_HPGLPenSize ); + plotter->SetPenOverlap( m_HPGLPenSize / 4 ); + plotter->StartPlot(); + + plotter->SetColor( BLACK ); + + if( getPlotFrameRef() ) + PlotWorkSheet( plotter, m_parent->GetTitleBlock(), + m_parent->GetPageSettings(), + aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens, + m_parent->GetScreenDesc(), + aScreen->GetFileName() ); + + aScreen->Plot( plotter ); + + plotter->EndPlot(); + delete plotter; + + return true; +} diff --git a/eeschema/plot_schematic_PDF.cpp b/eeschema/plot_schematic_PDF.cpp new file mode 100644 index 00000000..7fbdf117 --- /dev/null +++ b/eeschema/plot_schematic_PDF.cpp @@ -0,0 +1,209 @@ +/** @file plot_schematic_PDF.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2010 Jean-Pierre Charras +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotFrameRef ) +{ + SCH_SCREEN* screen = m_parent->GetScreen(); + SCH_SHEET_PATH* sheetpath; + SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); // sheetpath is saved here + + /* When printing all pages, the printed page is not the current page. In + * complex hierarchies, we must update component references and others + * parameters in the given printed SCH_SCREEN, accordint to the sheet path + * because in complex hierarchies a SCH_SCREEN (a drawing ) is shared + * between many sheets and component references depend on the actual sheet + * path used + */ + SCH_SHEET_LIST SheetList( NULL ); + + sheetpath = SheetList.GetFirst(); + + // Allocate the plotter and set the job level parameter + PDF_PLOTTER* plotter = new PDF_PLOTTER(); + plotter->SetDefaultLineWidth( GetDefaultLineThickness() ); + plotter->SetColorMode( getModeColor() ); + plotter->SetCreator( wxT( "Eeschema-PDF" ) ); + + wxString msg; + wxFileName plotFileName; + REPORTER& reporter = m_MessagesBox->Reporter(); + LOCALE_IO toggle; // Switch the locale to standard C + + // First page handling is different + bool first_page = true; + do + { + // Step over the schematic hierarchy + if( aPlotAll ) + { + SCH_SHEET_PATH list; + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + m_parent->SetCurrentSheet( list ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + screen = m_parent->GetCurrentSheet().LastScreen(); + } + else // Should not happen + wxASSERT( 0 ); + + sheetpath = SheetList.GetNext(); + } + + if( first_page ) + { + + try + { + wxString fname = m_parent->GetUniqueFilenameForCurrentSheet(); + wxString ext = PDF_PLOTTER::GetDefaultFileExtension(); + plotFileName = createPlotFileName( m_outputDirectoryName, + fname, ext, &reporter ); + + if( !plotter->OpenFile( plotFileName.GetFullPath() ) ) + { + msg.Printf( _( "Unable to create file '%s'.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + delete plotter; + return; + } + + // Open the plotter and do the first page + setupPlotPagePDF( plotter, screen ); + plotter->StartPlot(); + first_page = false; + + } + catch( const IO_ERROR& e ) + { + // Cannot plot PDF file + msg.Printf( wxT( "PDF Plotter exception: %s" ), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + + restoreEnvironment( plotter, oldsheetpath ); + return; + } + + } + else + { + /* For the following pages you need to close the (finished) page, + * reconfigure, and then start a new one */ + plotter->ClosePage(); + setupPlotPagePDF( plotter, screen ); + plotter->StartPage(); + } + + plotOneSheetPDF( plotter, screen, aPlotFrameRef ); + } while( aPlotAll && sheetpath ); + + // Everything done, close the plot and restore the environment + msg.Printf( _( "Plot: '%s' OK.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + + + restoreEnvironment(plotter, oldsheetpath ); + +} + + +void DIALOG_PLOT_SCHEMATIC::restoreEnvironment( PDF_PLOTTER* aPlotter, + SCH_SHEET_PATH& aOldsheetpath ) +{ + aPlotter->EndPlot(); + delete aPlotter; + + // Restore the previous sheet + m_parent->SetCurrentSheet( aOldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); +} + + +void DIALOG_PLOT_SCHEMATIC::plotOneSheetPDF( PLOTTER* aPlotter, + SCH_SCREEN* aScreen, + bool aPlotFrameRef ) +{ + if( aPlotFrameRef ) + { + aPlotter->SetColor( BLACK ); + PlotWorkSheet( aPlotter, m_parent->GetTitleBlock(), + m_parent->GetPageSettings(), + aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens, + m_parent->GetScreenDesc(), + aScreen->GetFileName() ); + } + + aScreen->Plot( aPlotter ); +} + + +void DIALOG_PLOT_SCHEMATIC::setupPlotPagePDF( PLOTTER * aPlotter, SCH_SCREEN* aScreen ) +{ + PAGE_INFO plotPage; // page size selected to plot + // Considerations on page size and scaling requests + PAGE_INFO actualPage = aScreen->GetPageSettings(); // page size selected in schematic + + switch( m_pageSizeSelect ) + { + case PAGE_SIZE_A: + plotPage.SetType( wxT( "A" ) ); + plotPage.SetPortrait( actualPage.IsPortrait() ); + break; + + case PAGE_SIZE_A4: + plotPage.SetType( wxT( "A4" ) ); + plotPage.SetPortrait( actualPage.IsPortrait() ); + break; + + case PAGE_SIZE_AUTO: + default: + plotPage = actualPage; + break; + } + + double scalex = (double) plotPage.GetWidthMils() / actualPage.GetWidthMils(); + double scaley = (double) plotPage.GetHeightMils() / actualPage.GetHeightMils(); + double scale = std::min( scalex, scaley ); + aPlotter->SetPageSettings( plotPage ); + aPlotter->SetViewport( wxPoint( 0, 0 ), IU_PER_DECIMILS, scale, false ); +} + diff --git a/eeschema/plot_schematic_PS.cpp b/eeschema/plot_schematic_PS.cpp new file mode 100644 index 00000000..9e1c1b4c --- /dev/null +++ b/eeschema/plot_schematic_PS.cpp @@ -0,0 +1,191 @@ +/** @file plot_schematic_PS.cpp + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2010 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void DIALOG_PLOT_SCHEMATIC::createPSFile( bool aPlotAll, bool aPlotFrameRef ) +{ + SCH_SCREEN* screen = m_parent->GetScreen(); + SCH_SHEET_PATH* sheetpath; + SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); // sheetpath is saved here + PAGE_INFO actualPage; // page size selected in schematic + PAGE_INFO plotPage; // page size selected to plot + + /* When printing all pages, the printed page is not the current page. + * In complex hierarchies, we must update component references + * and others parameters in the given printed SCH_SCREEN, accordint to the sheet path + * because in complex hierarchies a SCH_SCREEN (a drawing ) + * is shared between many sheets and component references depend on the actual sheet path used + */ + SCH_SHEET_LIST SheetList( NULL ); + + sheetpath = SheetList.GetFirst(); + SCH_SHEET_PATH list; + + while( true ) + { + if( aPlotAll ) + { + if( sheetpath == NULL ) + break; + + list.Clear(); + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + m_parent->SetCurrentSheet( list ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + screen = m_parent->GetCurrentSheet().LastScreen(); + } + else // Should not happen + return; + + sheetpath = SheetList.GetNext(); + } + + actualPage = screen->GetPageSettings(); + + switch( m_pageSizeSelect ) + { + case PAGE_SIZE_A: + plotPage.SetType( wxT( "A" ) ); + plotPage.SetPortrait( actualPage.IsPortrait() ); + break; + + case PAGE_SIZE_A4: + plotPage.SetType( wxT( "A4" ) ); + plotPage.SetPortrait( actualPage.IsPortrait() ); + break; + + case PAGE_SIZE_AUTO: + default: + plotPage = actualPage; + break; + } + + double scalex = (double) plotPage.GetWidthMils() / actualPage.GetWidthMils(); + double scaley = (double) plotPage.GetHeightMils() / actualPage.GetHeightMils(); + + double scale = std::min( scalex, scaley ); + + wxPoint plot_offset; + + wxString outputDirName = m_outputDirectoryName->GetValue(); + + wxString msg; + REPORTER& reporter = m_MessagesBox->Reporter(); + + try + { + wxString fname = m_parent->GetUniqueFilenameForCurrentSheet(); + wxString ext = PS_PLOTTER::GetDefaultFileExtension(); + wxFileName plotFileName = createPlotFileName( m_outputDirectoryName, + fname, ext, &reporter ); + + if( plotOneSheetPS( plotFileName.GetFullPath(), screen, plotPage, plot_offset, + scale, aPlotFrameRef ) ) + { + msg.Printf( _( "Plot: '%s' OK.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + } + else + { + // Error + msg.Printf( _( "Unable to create file '%s'.\n" ), GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + + } + catch( IO_ERROR& e ) + { + msg.Printf( wxT( "PS Plotter exception: %s"), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + + if( !aPlotAll ) + break; + } + + m_parent->SetCurrentSheet( oldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); +} + + +bool DIALOG_PLOT_SCHEMATIC::plotOneSheetPS( const wxString& aFileName, + SCH_SCREEN* aScreen, + const PAGE_INFO& aPageInfo, + wxPoint aPlot0ffset, + double aScale, + bool aPlotFrameRef ) +{ + PS_PLOTTER* plotter = new PS_PLOTTER(); + plotter->SetPageSettings( aPageInfo ); + plotter->SetDefaultLineWidth( GetDefaultLineThickness() ); + plotter->SetColorMode( getModeColor() ); + plotter->SetViewport( aPlot0ffset, IU_PER_DECIMILS, aScale, false ); + + // Init : + plotter->SetCreator( wxT( "Eeschema-PS" ) ); + + if( ! plotter->OpenFile( aFileName ) ) + { + delete plotter; + return false; + } + + LOCALE_IO toggle; // Switch the locale to standard C + + plotter->StartPlot(); + + if( aPlotFrameRef ) + { + plotter->SetColor( BLACK ); + PlotWorkSheet( plotter, m_parent->GetTitleBlock(), + m_parent->GetPageSettings(), + aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens, + m_parent->GetScreenDesc(), + aScreen->GetFileName() ); + } + + aScreen->Plot( plotter ); + + plotter->EndPlot(); + delete plotter; + + return true; +} diff --git a/eeschema/plot_schematic_SVG.cpp b/eeschema/plot_schematic_SVG.cpp new file mode 100644 index 00000000..0cc81ed8 --- /dev/null +++ b/eeschema/plot_schematic_SVG.cpp @@ -0,0 +1,205 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file plot_schematic_SVG.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void DIALOG_PLOT_SCHEMATIC::createSVGFile( bool aPrintAll, bool aPrintFrameRef ) +{ + wxString msg; + REPORTER& reporter = m_MessagesBox->Reporter(); + + if( aPrintAll ) + { + SCH_SHEET_PATH* sheetpath; + SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); + SCH_SHEET_LIST SheetList( NULL ); + sheetpath = SheetList.GetFirst(); + SCH_SHEET_PATH list; + + for( ; ; ) + { + if( sheetpath == NULL ) + { + break; + } + + SCH_SCREEN* screen; + list.Clear(); + + if( list.BuildSheetPathInfoFromSheetPathValue( sheetpath->Path() ) ) + { + m_parent->SetCurrentSheet( list ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + screen = m_parent->GetCurrentSheet().LastScreen(); + } + else // Should not happen + { + return; + } + + sheetpath = SheetList.GetNext(); + + try + { + wxString fname = m_parent->GetUniqueFilenameForCurrentSheet(); + wxString ext = SVG_PLOTTER::GetDefaultFileExtension(); + wxFileName plotFileName = createPlotFileName( m_outputDirectoryName, + fname, ext, &reporter ); + + bool success = plotOneSheetSVG( m_parent, plotFileName.GetFullPath(), screen, + getModeColor() ? false : true, + aPrintFrameRef ); + + if( !success ) + { + msg.Printf( _( "Cannot create file '%s'.\n" ), + GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + else + { + msg.Printf( _( "Plot: '%s' OK.\n" ), + GetChars( plotFileName.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + } + } + catch( const IO_ERROR& e ) + { + // Cannot plot SVG file + msg.Printf( wxT( "SVG Plotter exception: %s" ), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + + m_parent->SetCurrentSheet( oldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + return; + } + } + + m_parent->SetCurrentSheet( oldsheetpath ); + m_parent->GetCurrentSheet().UpdateAllScreenReferences(); + m_parent->SetSheetNumberAndCount(); + } + else // Print current sheet + { + SCH_SCREEN* screen = (SCH_SCREEN*) m_parent->GetScreen(); + + try + { + wxString fname = screen->GetFileName(); + wxString ext = SVG_PLOTTER::GetDefaultFileExtension(); + wxFileName fn = createPlotFileName( m_outputDirectoryName, fname, ext ); + + bool success = plotOneSheetSVG( m_parent, fn.GetFullPath(), screen, + getModeColor() ? false : true, + aPrintFrameRef ); + if( success ) + { + msg.Printf( _( "Plot: '%s' OK.\n" ), + GetChars( fn.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ACTION ); + + } + else // Error + { + msg.Printf( _( "Unable to create file '%s'.\n" ), + GetChars( fn.GetFullPath() ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + } + } + catch( const IO_ERROR& e ) + { + // Cannot plot SVG file + msg.Printf( wxT( "SVG Plotter exception: %s."), GetChars( e.errorText ) ); + reporter.Report( msg, REPORTER::RPT_ERROR ); + return; + } + } +} + + +bool DIALOG_PLOT_SCHEMATIC::plotOneSheetSVG( EDA_DRAW_FRAME* aFrame, + const wxString& aFileName, + SCH_SCREEN* aScreen, + bool aPlotBlackAndWhite, + bool aPlotFrameRef ) +{ + SVG_PLOTTER* plotter = new SVG_PLOTTER(); + + const PAGE_INFO& pageInfo = aScreen->GetPageSettings(); + plotter->SetPageSettings( pageInfo ); + plotter->SetDefaultLineWidth( GetDefaultLineThickness() ); + plotter->SetColorMode( aPlotBlackAndWhite ? false : true ); + wxPoint plot_offset; + double scale = 1.0; + plotter->SetViewport( plot_offset, IU_PER_DECIMILS, scale, false ); + + // Init : + plotter->SetCreator( wxT( "Eeschema-SVG" ) ); + + if( ! plotter->OpenFile( aFileName ) ) + { + delete plotter; + return false; + } + + LOCALE_IO toggle; + + plotter->StartPlot(); + + if( aPlotFrameRef ) + { + plotter->SetColor( BLACK ); + PlotWorkSheet( plotter, aFrame->GetTitleBlock(), + aFrame->GetPageSettings(), + aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens, + aFrame->GetScreenDesc(), + aScreen->GetFileName() ); + } + + aScreen->Plot( plotter ); + + plotter->EndPlot(); + delete plotter; + + return true; +} diff --git a/eeschema/plugins/CMakeLists.txt b/eeschema/plugins/CMakeLists.txt new file mode 100644 index 00000000..7ad2757d --- /dev/null +++ b/eeschema/plugins/CMakeLists.txt @@ -0,0 +1,30 @@ +# Install the *.xsl file(s), user will need to install 'xsltproc' and setup +# EESCHEMA's netlist plugins +# See chapter 14 of eeschema.pdf + + +set( XSL_SCRIPTS_LIST + xsl_scripts/bom_with_title_block_2_csv.xsl + xsl_scripts/bom2csv.xsl + xsl_scripts/bom2grouped_csv.xsl + xsl_scripts/netlist_form_cadstar-RINF.xsl + xsl_scripts/netlist_form_cadstar.xsl + xsl_scripts/netlist_form_OrcadPcb2.xsl + xsl_scripts/netlist_form_pads-pcb.xsl + ) + +set( PYTHON_SCRIPTS_LIST + python_scripts/README-bom.txt + python_scripts/kicad_netlist_reader.py + python_scripts/bom_csv_grouped_by_value.py + python_scripts/bom_csv_grouped_by_value_with_fp.py + python_scripts/bom_csv_sorted_by_ref.py + python_scripts/bom_html_grouped_by_value.py + python_scripts/bom_html_with_advanced_grouping.py + python_scripts/bom_sorted_by_ref.py + ) + +install( FILES ${XSL_SCRIPTS_LIST} ${PYTHON_SCRIPTS_LIST} + DESTINATION ${KICAD_PLUGINS} + COMPONENT binary + ) diff --git a/eeschema/plugins/python_scripts/README-bom.txt b/eeschema/plugins/python_scripts/README-bom.txt new file mode 100644 index 00000000..7a53d7d7 --- /dev/null +++ b/eeschema/plugins/python_scripts/README-bom.txt @@ -0,0 +1,38 @@ +bom_?.py are some python scripts which read a generic xml netlist from eeschema, +and create a bom. + +All examples use kicad_netlist_reader.py, which is a python utility to read +and parse this generic xml netlist and create the corresponding data +used to build the bom. + +You can modify them to build the bom you want. + +to use them, you should install python, and run: +python bom_example?.py + +See Eeschema doc, chapter 14 for info about the generic xml netlist format, +and how to run a script from Eeschema to create a customized netlist or BOM. + +If the python comment +""" + @package + some comments +""" +is added to the begining of the python script, the comment will be displayed +in Eescheam, in the BOM dialog + +For instance: +""" + @package + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor +""" + +displays: + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor +in BOM dialog diff --git a/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py new file mode 100644 index 00000000..b582d619 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py @@ -0,0 +1,167 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped CSV BOM +# +""" + @package + Generate a csv BOM list. + Components are sorted by ref and grouped by value + Fields are (if exist) + Item, Qty, Reference(s), Value, LibPart, Footprint, Datasheet + + Command line: + python "pathToFile/bom_csv_grouped_by_value.py" "%I" "%O.csv" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +def myEqu(self, other): + """myEqu is a more advanced equivalence function for components which is + used by component grouping. Normal operation is to group components based + on their value and footprint. + + In this example of a custom equivalency operator we compare the + value, the part name and the footprint. + """ + result = True + if self.getValue() != other.getValue(): + result = False + elif self.getPartName() != other.getPartName(): + result = False + elif self.getFootprint() != other.getFootprint(): + result = False + + return result + +# Override the component equivalence operator - it is important to do this +# before loading the netlist, otherwise all components will have the original +# equivalency operator. +kicad_netlist_reader.comp.__eq__ = myEqu + +if len(sys.argv) != 3: + print("Usage ", __file__, " ", file=sys.stderr) + sys.exit(1) + + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr ) + f = sys.stdout + +# subset the components to those wanted in the BOM, controlled +# by block in kicad_netlist_reader.py +components = net.getInterestingComponents() + +compfields = net.gatherComponentFieldUnion(components) +partfields = net.gatherLibPartFieldUnion() + +# remove Reference, Value, Datasheet, and Footprint, they will come from 'columns' below +partfields -= set( ['Reference', 'Value', 'Datasheet', 'Footprint'] ) + +columnset = compfields | partfields # union + +# prepend an initial 'hard coded' list and put the enchillada into list 'columns' +columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + +# Create a new csv writer object to use as the output formatter +out = csv.writer( f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL ) + +# override csv.writer's writerow() to support encoding conversion (initial encoding is utf8): +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col) ) # currently, no change + acsvwriter.writerow( utf8row ) + +# Output a set of rows as a header providing general information +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Generator:', sys.argv[0]] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, [] ) +writerow( out, ['Individual Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) + +# Output all the interesting components individually first: +row = [] +for c in components: + del row[:] + row.append('') # item is blank in individual table + row.append('') # Qty is always 1, why print it + row.append( c.getRef() ) # Reference + row.append( c.getValue() ) # Value + row.append( c.getLibName() + ":" + c.getPartName() ) # LibPart + #row.append( c.getDescription() ) + row.append( c.getFootprint() ) + row.append( c.getDatasheet() ) + + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( c.getField( field ) ); + + writerow( out, row ) + + +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line + +writerow( out, ['Collated Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) # reuse same columns + + + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + + +# Output component information organized by group, aka as collated: +item = 0 +for group in grouped: + del row[:] + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + # Fill in the component groups common data + # columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + item += 1 + row.append( item ) + row.append( len(group) ) + row.append( refs ); + row.append( c.getValue() ) + row.append( c.getLibName() + ":" + c.getPartName() ) + row.append( net.getGroupFootprint(group) ) + row.append( net.getGroupDatasheet(group) ) + + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( net.getGroupField(group, field) ); + + writerow( out, row ) + +f.close() diff --git a/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py new file mode 100644 index 00000000..dd14af09 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py @@ -0,0 +1,65 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped CSV BOM +# + +""" + @package + Generate a Tab delimited list (csv file type). + Components are sorted by ref and grouped by value with same footprint + Fields are (if exist) + 'Ref', 'Qnty', 'Value', 'Cmp name', 'Footprint', 'Description', 'Vendor' + + Command line: + python "pathToFile/bom_csv_grouped_by_value_with_fp.py" "%I" "%O.csv" +""" + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, sys.stderr) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter +out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL) + +# Output a set of rows for a header providing general information +out.writerow(['Source:', net.getSource()]) +out.writerow(['Date:', net.getDate()]) +out.writerow(['Tool:', net.getTool()]) +out.writerow( ['Generator:', sys.argv[0]] ) +out.writerow(['Component Count:', len(net.components)]) +out.writerow(['Ref', 'Qnty', 'Value', 'Cmp name', 'Footprint', 'Description', 'Vendor']) + +# Get all of the components in groups of matching parts + values +# (see ky_generic_netlist_reader.py) +grouped = net.groupComponents() + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + refs += component.getRef() + ", " + c = component + + # Fill in the component groups common data + out.writerow([refs, len(group), c.getValue(), c.getPartName(), c.getFootprint(), + c.getDescription(), c.getField("Vendor")]) + + diff --git a/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py b/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py new file mode 100644 index 00000000..e66cc132 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py @@ -0,0 +1,62 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Ungrouped (One component per row) CSV output +# + +""" + @package + Generate a csv list file. + Components are sorted by ref + One component per line + Fields are (if exist) + Ref, value, Part, footprint, Datasheet, Manufacturer, Vendor + + Command line: + python "pathToFile/bom_csv_sorted_by_ref.py" "%I" "%O.csv" +""" + +from __future__ import print_function + +# Import the KiCad python helper module +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr ) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter +out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL) + +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col) ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + +# Output a field delimited header line +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor'] ) + +# Output all of the component information (One component per row) +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getFootprint(), c.getDatasheet(), + c.getField("Manufacturer"), c.getField("Vendor")]) + diff --git a/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py b/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py new file mode 100644 index 00000000..80def664 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py @@ -0,0 +1,98 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped HTML BOM +# +""" + @package + Generate a HTML BOM list. + Components are sorted by ref and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor + + Command line: + python "pathToFile/bom_html_grouped_by_value.py" "%I" "%O.html" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +# Start with a basic html template +html = """ + + + + + + +

      +

      +

      +

      + + +
      + + + """ + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +components = net.getInterestingComponents() + +# Output a set of rows for a header providing general information +html = html.replace('', net.getSource()) +html = html.replace('', net.getDate()) +html = html.replace('', net.getTool()) +html = html.replace('', "Component Count:" + \ + str(len(components))) + +row = "Ref" +row += "Qnty" +row += "Value" + "Part" + "Datasheet" +row += "Description" + "Vendor" + +html = html.replace('', row + "") + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + row = "" + refs +"" + str(len(group)) + row += "" + c.getValue() + row += "" + c.getLibName() + ":" + c.getPartName() + row += "" + c.getDatasheet() + row += "" + c.getDescription() + row += "" + c.getField("Vendor")+ "" + + html = html.replace('', row + "") + +# Print the formatted html to the file +print(html, file=f) diff --git a/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py b/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py new file mode 100644 index 00000000..a0913515 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py @@ -0,0 +1,132 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped HTML BOM with advanced grouping +# + +""" + @package + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Footprint, Description, Vendor + + Command line: + python "pathToFile/bom_with_advanced_grouping.py" "%I" "%O.html" +""" + + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +# Start with a basic html template +html = """ + + + + + KiCad BOM Example 5 + + +

      +

      +

      +

      + + +
      + + + """ + +def myEqu(self, other): + """myEqu is a more advanced equivalence function for components which is + used by component grouping. Normal operation is to group components based + on their Value and Footprint. + + In this example of a more advanced equivalency operator we also compare the + custom fields Voltage, Tolerance and Manufacturer as well as the assigned + footprint. If these fields are not used in some parts they will simply be + ignored (they will match as both will be empty strings). + + """ + result = True + if self.getValue() != other.getValue(): + result = False + elif self.getPartName() != other.getPartName(): + result = False + elif self.getFootprint() != other.getFootprint(): + result = False + elif self.getField("Tolerance") != other.getField("Tolerance"): + result = False + elif self.getField("Manufacturer") != other.getField("Manufacturer"): + result = False + elif self.getField("Voltage") != other.getField("Voltage"): + result = False + + return result + +# Override the component equivalence operator - it is important to do this +# before loading the netlist, otherwise all components will have the original +# equivalency operator. +kicad_netlist_reader.comp.__eq__ = myEqu + +# Generate an instance of a generic netlist, and load the netlist tree from +# .tmp. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write too, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +# Output a set of rows for a header providing general information +html = html.replace('', net.getSource()) +html = html.replace('', net.getDate()) +html = html.replace('', net.getTool()) +html = html.replace('', "Component Count:" + \ + str(len(net.components))) + +row = "Ref" + "Qnty" +row += "Value" + "Part" + "Footprint" +row += "Description" + "Vendor" + +html = html.replace('', row + "") + +components = net.getInterestingComponents() + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + row = "\n " + row += "" + refs +"" + str(len(group)) + row += "" + c.getValue() + "" + c.getLibName() + ":" + row += c.getPartName() + "" + c.getFootprint() + "" + row += c.getDescription() + "" + c.getField("Vendor") + row += "" + + html = html.replace('', row + "") + +# Print the formatted html to output file +print(html, file=f) diff --git a/eeschema/plugins/python_scripts/bom_sorted_by_ref.py b/eeschema/plugins/python_scripts/bom_sorted_by_ref.py new file mode 100644 index 00000000..6dd28d57 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_sorted_by_ref.py @@ -0,0 +1,61 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +""" + @package + Generate a BOM list file (a simple text). + Components are sorted by ref + One component per line + Fields are (if exist) + Ref, Quantity, value, Part, footprint, Description, Vendor + Fields are separated by tabs + + Command line: + python "pathToFile/bom_sorted_by_ref.py" "%I" "%O.txt" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, sys.stderr) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter, although we +# are created a tab delimited list instead! +out = csv.writer(f, lineterminator='\n', delimiter='\t', quoting=csv.QUOTE_NONE) + +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + txt=str(col); + utf8row.append( txt ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + +# Output a field delimited header line +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Part', 'Footprint', 'Description', 'Vendor'] ) + +# Output all of the component information +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getLibName() + ":" + c.getPartName(), + c.getFootprint(), c.getDescription(), c.getField("Vendor")]) diff --git a/eeschema/plugins/python_scripts/kicad_netlist_reader.py b/eeschema/plugins/python_scripts/kicad_netlist_reader.py new file mode 100644 index 00000000..407f5725 --- /dev/null +++ b/eeschema/plugins/python_scripts/kicad_netlist_reader.py @@ -0,0 +1,764 @@ +# +# KiCad python module for interpreting generic netlists which can be used +# to generate Bills of materials, etc. +# +# Remember these files use UTF8 encoding +# +# No string formatting is used on purpose as the only string formatting that +# is current compatible with python 2.4+ to 3.0+ is the '%' method, and that +# is due to be deprecated in 3.0+ soon +# + +""" + @package + Helper module for interpreting generic netlist and build custom + bom generators or netlists in foreign format +""" + + +from __future__ import print_function +import sys +import xml.sax as sax +import re +import pdb + +#--------------------------------------------------------------------- + +# excluded_fields is a list of regular expressions. If any one matches a field +# from either a component or a libpart, then that will not be included as a +# column in the BOM. Otherwise all columns from all used libparts and components +# will be unionized and will appear. Some fields are impossible to blacklist, such +# as Ref, Value, Footprint, and Datasheet. Additionally Qty and Item are supplied +# unconditionally as columns, and may not be removed. +excluded_fields = [ + #'Price@1000' + ] + + +# You may exlude components from the BOM by either: +# +# 1) adding a custom field named "Installed" to your components and filling it +# with a value of "NU" (Normally Uninstalled). +# See netlist.getInterestingComponents(), or +# +# 2) blacklisting it in any of the three following lists: + + +# regular expressions which match component 'Reference' fields of components that +# are to be excluded from the BOM. +excluded_references = [ + 'TP[0-9]+' # all test points + ] + + +# regular expressions which match component 'Value' fields of components that +# are to be excluded from the BOM. +excluded_values = [ + 'MOUNTHOLE', + 'SCOPETEST', + 'MOUNT_HOLE', + 'SOLDER_BRIDGE.*' + ] + + +# regular expressions which match component 'Footprint' fields of components that +# are to be excluded from the BOM. +excluded_footprints = [ + #'MOUNTHOLE' + ] + +#-------------------------------------------------------------------- + + +class xmlElement(): + """xml element which can represent all nodes of the netlist tree. It can be + used to easily generate various output formats by propogating format + requests to children recursively. + """ + def __init__(self, name, parent=None): + self.name = name + self.attributes = {} + self.parent = parent + self.chars = "" + self.children = [] + + def __str__(self): + """String representation of this netlist element + + """ + return self.name + "[" + self.chars + "]" + " attr_count:" + str(len(self.attributes)) + + def formatXML(self, nestLevel=0, amChild=False): + """Return this element formatted as XML + + Keywords: + nestLevel -- increases by one for each level of nesting. + amChild -- If set to True, the start of document is not returned. + + """ + s = "" + + indent = "" + for i in range(nestLevel): + indent += " " + + if not amChild: + s = "\n" + + s += indent + "<" + self.name + for a in self.attributes: + s += " " + a + "=\"" + self.attributes[a] + "\"" + + if (len(self.chars) == 0) and (len(self.children) == 0): + s += "/>" + else: + s += ">" + self.chars + + for c in self.children: + s += "\n" + s += c.formatXML(nestLevel+1, True) + + if (len(self.children) > 0): + s += "\n" + indent + + if (len(self.children) > 0) or (len(self.chars) > 0): + s += "" + + return s + + def formatHTML(self, amChild=False): + """Return this element formatted as HTML + + Keywords: + amChild -- If set to True, the start of document is not returned + + """ + s = "" + + if not amChild: + s = """ + + + + + + + + """ + + s += "\n" + + for c in self.children: + s += c.formatHTML(True) + + if not amChild: + s += """
      " + self.name + "
      " + self.chars + "
        " + for a in self.attributes: + s += "
      • " + a + " = " + self.attributes[a] + "
      • " + + s += "
      + + """ + + return s + + def addAttribute(self, attr, value): + """Add an attribute to this element""" + if type(value) != str: value = value.encode('utf-8') + self.attributes[attr] = value + + def setAttribute(self, attr, value): + """Set an attributes value - in fact does the same thing as add + attribute + + """ + self.attributes[attr] = value + + def setChars(self, chars): + """Set the characters for this element""" + self.chars = chars + + def addChars(self, chars): + """Add characters (textual value) to this element""" + self.chars += chars + + def addChild(self, child): + """Add a child element to this element""" + self.children.append(child) + return self.children[len(self.children) - 1] + + def getParent(self): + """Get the parent of this element (Could be None)""" + return self.parent + + def getChild(self, name): + """Returns the first child element named 'name' + + Keywords: + name -- The name of the child element to return""" + for child in self.children: + if child.name == name: + return child + return None + + def getChildren(self, name=None): + if name: + # return _all_ children named "name" + ret = [] + for child in self.children: + if child.name == name: + ret.append(child) + return ret + else: + return self.children + + def get(self, elemName, attribute="", attrmatch=""): + """Return the text data for either an attribute or an xmlElement + """ + if (self.name == elemName): + if attribute != "": + try: + if attrmatch != "": + if self.attributes[attribute] == attrmatch: + ret = self.chars + if type(ret) != str: ret = ret.encode('utf-8') + return ret + else: + ret = self.attributes[attribute] + if type(ret) != str: ret = ret.encode('utf-8') + return ret + except AttributeError: + ret = "" + if type(ret) != str: ret = ret.encode('utf-8') + return ret + else: + ret = self.chars + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + for child in self.children: + ret = child.get(elemName, attribute, attrmatch) + if ret != "": + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + ret = "" + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + + +class libpart(): + """Class for a library part, aka 'libpart' in the xml netlist file. + (Components in eeschema are instantiated from library parts.) + This part class is implemented by wrapping an xmlElement with accessors. + This xmlElement instance is held in field 'element'. + """ + def __init__(self, xml_element): + # + self.element = xml_element + + #def __str__(self): + # simply print the xmlElement associated with this part + #return str(self.element) + + def getLibName(self): + return self.element.get("libpart", "lib") + + def getPartName(self): + return self.element.get("libpart", "part") + + def getDescription(self): + return self.element.get("description") + + def getField(self, name): + return self.element.get("field", "name", name) + + def getFieldNames(self): + """Return a list of field names in play for this libpart. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getDatasheet(self): + return self.getField("Datasheet") + + def getFootprint(self): + return self.getField("Footprint") + + def getAliases(self): + """Return a list of aliases or None""" + aliases = self.element.getChild("aliases") + if aliases: + ret = [] + children = aliases.getChildren() + # grab the text out of each child: + for child in children: + ret.append( child.get("alias") ) + return ret + return None + + +class comp(): + """Class for a component, aka 'comp' in the xml netlist file. + This component class is implemented by wrapping an xmlElement instance + with accessors. The xmlElement is held in field 'element'. + """ + + def __init__(self, xml_element): + self.element = xml_element + self.libpart = None + + # Set to true when this component is included in a component group + self.grouped = False + + def __eq__(self, other): + """ Equivalency operator, remember this can be easily overloaded + 2 components are equivalent ( i.e. can be grouped + if they have same value and same footprint + + Override the component equivalence operator must be done before + loading the netlist, otherwise all components will have the original + equivalency operator. + + You have to define a comparison module (for instance named myEqu) + and add the line; + kicad_netlist_reader.comp.__eq__ = myEqu + in your bom generator script before calling the netliste reader by something like: + net = kicad_netlist_reader.netlist(sys.argv[1]) + """ + result = False + if self.getValue() == other.getValue(): + if self.getFootprint() == other.getFootprint(): + result = True + return result + + def setLibPart(self, part): + self.libpart = part + + def getLibPart(self): + return self.libpart + + def getPartName(self): + return self.element.get("libsource", "part") + + def getLibName(self): + return self.element.get("libsource", "lib") + + def setValue(self, value): + """Set the value of this component""" + v = self.element.getChild("value") + if v: + v.setChars(value) + + def getValue(self): + return self.element.get("value") + + def getField(self, name, libraryToo=True): + """Return the value of a field named name. The component is first + checked for the field, and then the components library part is checked + for the field. If the field doesn't exist in either, an empty string is + returned + + Keywords: + name -- The name of the field to return the value for + libraryToo -- look in the libpart's fields for the same name if not found + in component itself + """ + + field = self.element.get("field", "name", name) + if field == "" and libraryToo: + field = self.libpart.getField(name) + return field + + def getFieldNames(self): + """Return a list of field names in play for this component. Mandatory + fields are not included, and they are: Value, Footprint, Datasheet, Ref. + The netlist format only includes fields with non-empty values. So if a field + is empty, it will not be present in the returned list. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getRef(self): + return self.element.get("comp", "ref") + + def getFootprint(self, libraryToo=True): + ret = self.element.get("footprint") + if ret =="" and libraryToo: + ret = self.libpart.getFootprint() + return ret + + def getDatasheet(self, libraryToo=True): + ret = self.element.get("datasheet") + if ret == '' and libraryToo: + ret = self.libpart.getDatasheet() + return ret + + def getTimestamp(self): + return self.element.get("tstamp") + + def getDescription(self): + return self.libpart.getDescription() + + +class netlist(): + """ Kicad generic netlist class. Generally loaded from a kicad generic + netlist file. Includes several helper functions to ease BOM creating + scripts + + """ + def __init__(self, fname=""): + """Initialiser for the genericNetlist class + + Keywords: + fname -- The name of the generic netlist file to open (Optional) + + """ + self.design = None + self.components = [] + self.libparts = [] + self.libraries = [] + self.nets = [] + + # The entire tree is loaded into self.tree + self.tree = [] + + self._curr_element = None + + # component blacklist regexs, made from exluded_* above. + self.excluded_references = [] + self.excluded_values = [] + self.excluded_footprints = [] + + if fname != "": + self.load(fname) + + def addChars(self, content): + """Add characters to the current element""" + self._curr_element.addChars(content) + + def addElement(self, name): + """Add a new kicad generic element to the list""" + if self._curr_element == None: + self.tree = xmlElement(name) + self._curr_element = self.tree + else: + self._curr_element = self._curr_element.addChild( + xmlElement(name, self._curr_element)) + + # If this element is a component, add it to the components list + if self._curr_element.name == "comp": + self.components.append(comp(self._curr_element)) + + # Assign the design element + if self._curr_element.name == "design": + self.design = self._curr_element + + # If this element is a library part, add it to the parts list + if self._curr_element.name == "libpart": + self.libparts.append(libpart(self._curr_element)) + + # If this element is a net, add it to the nets list + if self._curr_element.name == "net": + self.nets.append(self._curr_element) + + # If this element is a library, add it to the libraries list + if self._curr_element.name == "library": + self.libraries.append(self._curr_element) + + return self._curr_element + + def endDocument(self): + """Called when the netlist document has been fully parsed""" + # When the document is complete, the library parts must be linked to + # the components as they are seperate in the tree so as not to + # duplicate library part information for every component + for c in self.components: + for p in self.libparts: + if p.getLibName() == c.getLibName(): + if p.getPartName() == c.getPartName(): + c.setLibPart(p) + break + else: + aliases = p.getAliases() + if aliases and self.aliasMatch( c.getPartName(), aliases ): + c.setLibPart(p) + break; + + if not c.getLibPart(): + print( 'missing libpart for ref:', c.getRef(), c.getPartName(), c.getLibName() ) + + + def aliasMatch(self, partName, aliasList): + for alias in aliasList: + if partName == alias: + return True + return False + + def endElement(self): + """End the current element and switch to its parent""" + self._curr_element = self._curr_element.getParent() + + def getDate(self): + """Return the date + time string generated by the tree creation tool""" + return self.design.get("date") + + def getSource(self): + """Return the source string for the design""" + return self.design.get("source") + + def getTool(self): + """Return the tool string which was used to create the netlist tree""" + return self.design.get("tool") + + def gatherComponentFieldUnion(self, components=None): + """Gather the complete 'set' of unique component fields, fields found in any component. + """ + if not components: + components=self.components + + s = set() + for c in components: + s.update( c.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def gatherLibPartFieldUnion(self): + """Gather the complete 'set' of part fields, fields found in any part. + """ + s = set() + for p in self.libparts: + s.update( p.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def getInterestingComponents(self): + """Return a subset of all components, those that should show up in the BOM. + Omit those that should not, by consulting the blacklists: + excluded_values, excluded_refs, and excluded_footprints, which hold one + or more regular expressions. If any of the the regular expressions match + the corresponding field's value in a component, then the component is exluded. + """ + + # pre-compile all the regex expressions: + del self.excluded_references[:] + del self.excluded_values[:] + del self.excluded_footprints[:] + + for rex in excluded_references: + self.excluded_references.append( re.compile( rex ) ) + + for rex in excluded_values: + self.excluded_values.append( re.compile( rex ) ) + + for rex in excluded_footprints: + self.excluded_footprints.append( re.compile( rex ) ) + + # the subset of components to return, considered as "interesting". + ret = [] + + # run each component thru a series of tests, if it passes all, then add it + # to the interesting list 'ret'. + for c in self.components: + exclude = False + if not exclude: + for refs in self.excluded_references: + if refs.match(c.getRef()): + exclude = True + break; + if not exclude: + for vals in self.excluded_values: + if vals.match(c.getValue()): + exclude = True + break; + if not exclude: + for mods in self.excluded_footprints: + if mods.match(c.getFootprint()): + exclude = True + break; + + if not exclude: + # This is a fairly personal way to flag DNS (Do Not Stuff). NU for + # me means Normally Uninstalled. You can 'or in' another expression here. + if c.getField( "Installed" ) == 'NU': + exclude = True + + if not exclude: + ret.append(c) + + # Sort first by ref as this makes for easier to read BOM's + def f(v): + return re.sub(r'([A-z]+)[0-9]+', r'\1', v) + '%08i' % int(re.sub(r'[A-z]+([0-9]+)', r'\1', v)) + ret.sort(key=lambda g: f(g.getRef())) + + return ret + + + def groupComponents(self, components = None): + """Return a list of component lists. Components are grouped together + when the value, library and part identifiers match. + + Keywords: + components -- is a list of components, typically an interesting subset + of all components, or None. If None, then all components are looked at. + """ + if not components: + components = self.components + + groups = [] + + # Make sure to start off will all components ungrouped to begin with + for c in components: + c.grouped = False + + # Group components based on the value, library and part identifiers + for c in components: + if c.grouped == False: + c.grouped = True + newgroup = [] + newgroup.append(c) + + # Check every other ungrouped component against this component + # and add to the group as necessary + for ci in components: + if ci.grouped == False and ci == c: + newgroup.append(ci) + ci.grouped = True + + # Add the new component group to the groups list + groups.append(newgroup) + + # Each group is a list of components, we need to sort each list first + # to get them in order as this makes for easier to read BOM's + def f(v): + return re.sub(r'([A-z]+)[0-9]+', r'\1', v) + '%08i' % int(re.sub(r'[A-z]+([0-9]+)', r'\1', v)) + for g in groups: + g = sorted(g, key=lambda g: f(g.getRef())) + + # Finally, sort the groups to order the references alphabetically + groups = sorted(groups, key=lambda group: f(group[0].getRef())) + + return groups + + def getGroupField(self, group, field): + """Return the whatever is known about the given field by consulting each + component in the group. If any of them know something about the property/field, + then return that first non-blank value. + """ + for c in group: + ret = c.getField(field, False) + if ret != '': + return ret + return group[0].getLibPart().getField(field) + + def getGroupFootprint(self, group): + """Return the whatever is known about the Footprint by consulting each + component in the group. If any of them know something about the Footprint, + then return that first non-blank value. + """ + for c in group: + ret = c.getFootprint() + if ret != "": + return ret + return group[0].getLibPart().getFootprint() + + def getGroupDatasheet(self, group): + """Return the whatever is known about the Datasheet by consulting each + component in the group. If any of them know something about the Datasheet, + then return that first non-blank value. + """ + for c in group: + ret = c.getDatasheet() + if ret != "": + return ret + + if len(group) > 0: + return group[0].getLibPart().getDatasheet() + else: + print("NULL!") + return '' + + def formatXML(self): + """Return the whole netlist formatted in XML""" + return self.tree.formatXML() + + def formatHTML(self): + """Return the whole netlist formatted in HTML""" + return self.tree.formatHTML() + + def load(self, fname): + """Load a kicad generic netlist + + Keywords: + fname -- The name of the generic netlist file to open + + """ + try: + self._reader = sax.make_parser() + self._reader.setContentHandler(_gNetReader(self)) + self._reader.parse(fname) + except IOError as e: + print( __file__, ":", e, file=sys.stderr ) + sys.exit(-1) + + + +class _gNetReader(sax.handler.ContentHandler): + """SAX kicad generic netlist content handler - passes most of the work back + to the 'netlist' class which builds a complete tree in RAM for the design + + """ + def __init__(self, aParent): + self.parent = aParent + + def startElement(self, name, attrs): + """Start of a new XML element event""" + element = self.parent.addElement(name) + + for name in attrs.getNames(): + element.addAttribute(name, attrs.getValue(name)) + + def endElement(self, name): + self.parent.endElement() + + def characters(self, content): + # Ignore erroneous white space - ignoreableWhitespace does not get rid + # of the need for this! + if not content.isspace(): + self.parent.addChars(content) + + def endDocument(self): + """End of the XML document event""" + self.parent.endDocument() diff --git a/eeschema/plugins/python_scripts/round_robin.py b/eeschema/plugins/python_scripts/round_robin.py new file mode 100644 index 00000000..0f15e6f2 --- /dev/null +++ b/eeschema/plugins/python_scripts/round_robin.py @@ -0,0 +1,28 @@ +# +# Example python script to generate an equivalent XML document from XML input +# +# Example: Round robin, XML to XML conversion +# + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys +import pdb + + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr) + f = sys.stdout + +print(net.formatXML(), file=f) diff --git a/eeschema/plugins/python_scripts/round_value_robin.py b/eeschema/plugins/python_scripts/round_value_robin.py new file mode 100644 index 00000000..e1bf3ff5 --- /dev/null +++ b/eeschema/plugins/python_scripts/round_value_robin.py @@ -0,0 +1,74 @@ +# +# Example python script to generate an equivalent XML document from XML input +# +# Example: Round value robin, XML to XML conversion with partial value monging +# + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +def checkvalue(self): + """Check values, and replace with preferred/consistent values""" + ref = self.getRef() + r = ref.split("R") + c = ref.split("C") + v = self.getValue() + + # Common to all values - convert decimation if necessary + dec = v.split(",") + if (len(dec) == 2): + newval = dec[0] + "." + dec[1] + self.setValue(newval) + v = self.getValue() + + if len(r) == 2 and r[1].isdigit(): + # This is a resistor - make values consistent + # If the value is a pure value, add R to the end of the value + if v.isdigit(): + i = int(v) + if (i > 1000000): + i = i / 1000000 + v = str(i) + "M" + if (i > 1000): + i = i / 1000 + v = str(i) + "K" + else: + v = str(i) + "R" + + self.setValue(v) + else: + # Get the multiplier character + multiplier = v[len(v) - 1] + v = v.strip(multiplier) + v = v.split(".") + if (len(v) == 2): + newval = v[0] + multiplier + v[1] + self.setValue(newval) + v = self.getValue() + + + +# Give components a new method for checking the values (this could easily be a +# Company Part Number generator method instead) +kicad_netlist_reader.comp.checkvalue = checkvalue + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +for c in net.components: + c.checkvalue() + +print(net.formatXML(), file=f) diff --git a/eeschema/plugins/xsl_scripts/bom2csv.xsl b/eeschema/plugins/xsl_scripts/bom2csv.xsl new file mode 100644 index 00000000..67d588b3 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom2csv.xsl @@ -0,0 +1,99 @@ + + + + + +]> + + + + + + + + + + + Reference, Value, Footprint, Datasheet + + + + , + + + &nl; + + + + + + + + " + "," + "," + "," + " + + &nl; + + + + + + + + + + + + ," + + + + + + + + + + + + + " + + + + diff --git a/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl b/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl new file mode 100644 index 00000000..e9b84466 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl @@ -0,0 +1,104 @@ + + + + + +]> + + + + + + + + + + + + + + Reference, Quantity, Value, Footprint, Datasheet + + + + , + + + + + + + + + + + + &nl; + + + + + , + + , + " + "," + "," + " + + + + + + + + + + + + + + ," + + + + + + + + + " + + + + + + + \ No newline at end of file diff --git a/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl b/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl new file mode 100644 index 00000000..feed1cea --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl @@ -0,0 +1,167 @@ + + + + +]> + + + + + + + + + + Source,&nl; + Kicad Rev,&nl; + Generated Date,&nl; + + &nl; + + + + + &nl; + + + Reference,Value, + + + , + + Library,Library Ref + &nl; + + + + + + + + + + + Title,&nl; + + + Title,Not Set&nl; + + + + + + + Company,&nl; + + + Company,Not Set&nl; + + + + + + Revision,&nl; + + + Revision,Not Set&nl; + + + + + + Date Issue,&nl; + + + Date Issue,Not Set&nl; + + + + + + + + + + + Comment,&nl; + + + + + + + + + , + , + + + &nl; + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + , + + + + diff --git a/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl b/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl new file mode 100644 index 00000000..30177110 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl @@ -0,0 +1,210 @@ + + + + +]> + + + + + + + ( { EESchema Netlist Version 1.1 + + + + + }&nl; + + + + + + )&nl;*&nl; + + + + + + + + + + + &nl; + + + + + ( + + + + + + 00000000 + + + + + + + + + $noname + + + + + + + + + + + "~" + + + &nl; + + + + + )&nl; + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + + + + + + + + + + )&nl; + + + + + + + + + + + + + + + + + + + + $N-0 + + + + + ? + + + + + + + diff --git a/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl b/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl new file mode 100644 index 00000000..7df4b76a --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl @@ -0,0 +1,131 @@ + + + + +]> + + + + + + + .HEA&nl; + + + &nl; + + &nl;&nl; + + &nl;.END&nl; + + + + + .APP " + + "&nl; + + + + + .TIM + + &nl; + + + + + + .ADD_COM + + + + + + + + ? + + + + + + + + + + + &nl; + + + + + + + + + + + + + + + N- + + + + &nl; + + + + + + + + + + + .ADD_TER + + . + + + + + + + + + + + .TER + + + + + + + + . + + &nl; + + + + diff --git a/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl b/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl new file mode 100644 index 00000000..0c72f53a --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl @@ -0,0 +1,123 @@ + + + + +]> + + + + + + + .HEA&nl; + + + &nl; + + &nl;&nl; + + &nl;.END&nl; + + + + + .APP " + + "&nl; + + + + + .TIM + + &nl; + + + + + + .ADD_COM + + + + + " " + + + "" + + + &nl; + + + + + + + + + " + + + + + + N- + + + + "&nl; + + + + + + + + + + + .ADD_TER + + . + + + + + + + + + + + .TER + + + + + + + + . + + &nl; + + + + diff --git a/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl b/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl new file mode 100644 index 00000000..355072c5 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl @@ -0,0 +1,69 @@ + + + + +]> + + + + + + *PADS-PCB*&nl;*PART*&nl; + + &nl;*NET*&nl; + + *END*&nl; + + + + + + + + + + + + + unknown + + + &nl; + + + + + + + *SIGNAL* + + + + + + N- + + + + &nl; + + + + + + + + + . + + &nl; + + + diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp new file mode 100644 index 00000000..098d3a37 --- /dev/null +++ b/eeschema/project_rescue.cpp @@ -0,0 +1,569 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Chris Pavlina + * Copyright (C) 2015 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef std::pair COMPONENT_NAME_PAIR; + + +/** + * Function save_library + * writes the library out to disk. Returns true on success. + * + * @param aFileName - Filename to receive the library + * @param aLibrary - Library to write + * @param aEditFrame - the calling SCH_EDIT_FRAME + */ +static bool save_library( const wxString& aFileName, PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame ) +{ + try + { + FILE_OUTPUTFORMATTER formatter( aFileName ); + + if( !aLibrary->Save( formatter ) ) + { + wxString msg = wxString::Format( _( + "An error occurred attempting to save component library '%s'." ), + GetChars( aFileName ) + ); + DisplayError( aEditFrame, msg ); + return false; + } + } + catch( ... /* IO_ERROR ioe */ ) + { + wxString msg = wxString::Format( _( + "Failed to create component library file '%s'" ), + GetChars( aFileName ) + ); + DisplayError( aEditFrame, msg ); + return false; + } + + return true; +} + + +/** + * Function insert_library + * inserts a library into the project and refreshes libraries. + * + * @param aProject - project that will be modified + * @param aLibrary - PART_LIB to add + * @param aIndex - index in the list at which the library is to be inserted + * + * @return true on success, false on failure + */ +static bool insert_library( PROJECT *aProject, PART_LIB *aLibrary, size_t aIndex ) throw( boost::bad_pointer ) +{ + wxArrayString libNames; + wxString libPaths; + + wxString libName = aLibrary->GetName(); + PART_LIBS *libs = dynamic_cast( aProject->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) ); + if( !libs ) + { + libs = new PART_LIBS(); + aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs ); + } + + try + { + PART_LIBS::LibNamesAndPaths( aProject, false, &libPaths, &libNames ); + + // Make sure the library is not already in the list + while( libNames.Index( libName ) != wxNOT_FOUND ) + libNames.Remove( libName ); + + // Add the library to the list and save + libNames.Insert( libName, aIndex ); + PART_LIBS::LibNamesAndPaths( aProject, true, &libPaths, &libNames ); + } + catch( const IO_ERROR& e ) + { + // Could not get or save the current libraries. + return false; + } + + // Save the old libraries in case there is a problem after clear(). We'll + // put them back in. + boost::ptr_vector libsSave; + libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs ); + + aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL ); + + libs = new PART_LIBS(); + try + { + libs->LoadAllLibraries( aProject ); + } + catch( const PARSE_ERROR& e ) + { + // Some libraries were not found. There's no point in showing the error, + // because it was already shown. Just don't do anything. + } + catch( const IO_ERROR& e ) + { + // Restore the old list + libs->clear(); + libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave ); + return false; + } + aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs ); + + return true; +} + + +/** + * Function get_components + * Fills a vector with all of the project's components, to ease iterating over them. + * + * @param aComponents - a vector that will take the components + */ +static void get_components( std::vector& aComponents ) +{ + SCH_SCREENS screens; + for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() ) + { + for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) continue; + SCH_COMPONENT* component = dynamic_cast( item ); + aComponents.push_back( component ); + } + } +} + + +/** + * Function find_component + * Search the libraries for the first component with a given name. + * + * @param aName - name to search for + * @param aLibs - the loaded PART_LIBS + * @param aCached - whether we are looking for the cached part + */ +static LIB_PART* find_component( wxString aName, PART_LIBS* aLibs, bool aCached ) +{ + LIB_PART *part = NULL; + + BOOST_FOREACH( PART_LIB& each_lib, *aLibs ) + { + if( aCached && !each_lib.IsCache() ) + continue; + + if( !aCached && each_lib.IsCache() ) + continue; + + part = each_lib.FindPart( aName ); + if( part ) + break; + } + + return part; +} + + +void RESCUER::RemoveDuplicates() +{ + std::vector names_seen; + + for( boost::ptr_vector::iterator it = m_all_candidates.begin(); + it != m_all_candidates.end(); ) + { + bool seen_already = false; + BOOST_FOREACH( wxString& name_seen, names_seen ) + { + if( name_seen == it->GetRequestedName() ) + { + seen_already = true; + break; + } + } + + if( seen_already ) + { + it = m_all_candidates.erase( it ); + } + else + { + names_seen.push_back( it->GetRequestedName() ); + ++it; + } + } +} + + +class RESCUE_CASE_CANDIDATE: public RESCUE_CANDIDATE +{ + wxString m_requested_name; + wxString m_new_name; + LIB_PART* m_lib_candidate; + +public: + /** + * Function FindRescues + * Grab all possible RESCUE_CASE_CANDIDATES into a vector. + * @param aRescuer - the working RESCUER instance. + * @param aCandidates - the vector the will hold the candidates. + */ + static void FindRescues( RESCUER& aRescuer, boost::ptr_vector& aCandidates ) + { + typedef std::map candidate_map_t; + candidate_map_t candidate_map; + + BOOST_FOREACH( SCH_COMPONENT* each_component, *( aRescuer.GetComponents() ) ) + { + wxString part_name( each_component->GetPartName() ); + + LIB_ALIAS* case_sensitive_match = aRescuer.GetLibs()->FindLibraryEntry( part_name ); + std::vector case_insensitive_matches; + aRescuer.GetLibs()->FindLibraryNearEntries( case_insensitive_matches, part_name ); + + if( case_sensitive_match || !( case_insensitive_matches.size() ) ) + continue; + + RESCUE_CASE_CANDIDATE candidate( + part_name, case_insensitive_matches[0]->GetName(), + case_insensitive_matches[0]->GetPart() ); + candidate_map[part_name] = candidate; + } + + // Now, dump the map into aCandidates + BOOST_FOREACH( const candidate_map_t::value_type& each_pair, candidate_map ) + { + aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) ); + } + } + + /** + * Constructor RESCUE_CANDIDATE + * @param aRequestedName - the name the schematic asks for + * @param aNewName - the name we want to change it to + * @param aLibCandidate - the part that will give us + */ + RESCUE_CASE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName, + LIB_PART* aLibCandidate ) + : m_requested_name( aRequestedName ), + m_new_name( aNewName ), + m_lib_candidate( aLibCandidate ) { } + + RESCUE_CASE_CANDIDATE() { m_lib_candidate = NULL; } + + virtual wxString GetRequestedName() const { return m_requested_name; } + virtual wxString GetNewName() const { return m_new_name; } + virtual LIB_PART* GetLibCandidate() const { return m_lib_candidate; } + virtual wxString GetActionDescription() const + { + wxString action; + action.Printf( _( "Rename to %s" ), m_new_name ); + return action; + } + + virtual bool PerformAction( RESCUER* aRescuer ) + { + BOOST_FOREACH( SCH_COMPONENT* each_component, *aRescuer->GetComponents() ) + { + if( each_component->GetPartName() != m_requested_name ) continue; + each_component->SetPartName( m_new_name ); + each_component->ClearFlags(); + aRescuer->LogRescue( each_component, m_requested_name, m_new_name ); + } + return true; + } +}; + + +class RESCUE_CACHE_CANDIDATE: public RESCUE_CANDIDATE +{ + wxString m_requested_name; + wxString m_new_name; + LIB_PART* m_cache_candidate; + LIB_PART* m_lib_candidate; + + static std::auto_ptr m_rescue_lib; + static wxFileName m_library_fn; + +public: + /** + * Function FindRescues + * Grab all possible RESCUE_CACHE_CANDIDATEs into a vector. + * @param aRescuer - the working RESCUER instance. + * @param aCandidates - the vector the will hold the candidates. + */ + static void FindRescues( RESCUER& aRescuer, boost::ptr_vector& aCandidates ) + { + typedef std::map candidate_map_t; + candidate_map_t candidate_map; + + wxString part_name_suffix = aRescuer.GetPartNameSuffix(); + + BOOST_FOREACH( SCH_COMPONENT* each_component, *( aRescuer.GetComponents() ) ) + { + wxString part_name( each_component->GetPartName() ); + + LIB_PART* cache_match = find_component( part_name, aRescuer.GetLibs(), /* aCached */ true ); + LIB_PART* lib_match = aRescuer.GetLibs()->FindLibPart( part_name ); + + // Test whether there is a conflict + if( !cache_match || !lib_match ) + continue; + if( !cache_match->PinsConflictWith( *lib_match, /* aTestNums */ true, + /* aTestNames */ true, /* aTestType */ true, /* aTestOrientation */ true, + /* aTestLength */ false )) + continue; + + RESCUE_CACHE_CANDIDATE candidate( + part_name, part_name + part_name_suffix, + cache_match, lib_match ); + candidate_map[part_name] = candidate; + } + + // Now, dump the map into aCandidates + BOOST_FOREACH( const candidate_map_t::value_type& each_pair, candidate_map ) + { + aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) ); + } + } + + /** + * Constructor RESCUE_CACHE_CANDIDATE + * @param aRequestedName - the name the schematic asks for + * @param aNewName - the name we want to change it to + * @param aCacheCandidate - the part from the cache + * @param aLibCandidate - the part that would be loaded from the library + */ + RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName, + LIB_PART* aCacheCandidate, LIB_PART* aLibCandidate ) + : m_requested_name( aRequestedName ), + m_new_name( aNewName ), + m_cache_candidate( aCacheCandidate ), + m_lib_candidate( aLibCandidate ) { } + + RESCUE_CACHE_CANDIDATE() + : m_cache_candidate( NULL ), m_lib_candidate( NULL ) {} + + virtual wxString GetRequestedName() const { return m_requested_name; } + virtual wxString GetNewName() const { return m_new_name; } + virtual LIB_PART* GetCacheCandidate() const { return m_cache_candidate; } + virtual LIB_PART* GetLibCandidate() const { return m_lib_candidate; } + virtual wxString GetActionDescription() const + { + wxString action; + action.Printf( _( "Rescue %s as %s" ), m_requested_name, m_new_name ); + return action; + } + + /** + * Function OpenRescueLibrary + * Creates the new rescue library. Must be called before calling any PerformAction()s. + */ + static void OpenRescueLibrary() + { + wxFileName fn( g_RootSheet->GetScreen()->GetFileName() ); + fn.SetName( fn.GetName() + wxT( "-rescue" ) ); + fn.SetExt( SchematicLibraryFileExtension ); + m_library_fn.SetPath( fn.GetPath() ); + m_library_fn.SetName( fn.GetName() ); + m_library_fn.SetExt( wxT( "lib" ) ); + + std::auto_ptr rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, + fn.GetFullPath() ) ); + + m_rescue_lib = rescue_lib; + } + + virtual bool PerformAction( RESCUER* aRescuer ) + { + LIB_PART new_part( *m_cache_candidate, m_rescue_lib.get() ); + new_part.SetName( m_new_name ); + new_part.RemoveAllAliases(); + RESCUE_CACHE_CANDIDATE::m_rescue_lib.get()->AddPart( &new_part ); + + BOOST_FOREACH( SCH_COMPONENT* each_component, *aRescuer->GetComponents() ) + { + if( each_component->GetPartName() != m_requested_name ) continue; + each_component->SetPartName( m_new_name ); + each_component->ClearFlags(); + aRescuer->LogRescue( each_component, m_requested_name, m_new_name ); + } + return true; + } + + /** + * Function WriteRescueLibrary + * Writes out the rescue library. Called after successful PerformAction()s. If this fails, + * undo the actions. + * @return True on success. + */ + static bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame, PROJECT* aProject ) + { + + if( !save_library( m_library_fn.GetFullPath(), m_rescue_lib.get(), aEditFrame ) ) + return false; + return insert_library( aProject, m_rescue_lib.get(), 0 ); + } +}; + +std::auto_ptr RESCUE_CACHE_CANDIDATE::m_rescue_lib; +wxFileName RESCUE_CACHE_CANDIDATE::m_library_fn; + +RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject ) +{ + get_components( m_components ); + m_prj = &aProject; + m_libs = m_prj->SchLibs(); + m_edit_frame = &aEditFrame; +} + + +void RESCUER::FindCandidates() +{ + RESCUE_CASE_CANDIDATE::FindRescues( *this, m_all_candidates ); + RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates ); +} + + +void RESCUER::InvokeDialog( bool aAskShowAgain ) +{ + InvokeDialogRescueEach( m_edit_frame, *this, aAskShowAgain ); +} + + +void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName, + const wxString &aNewName ) +{ + RESCUE_LOG logitem; + logitem.component = aComponent; + logitem.old_name = aOldName; + logitem.new_name = aNewName; + m_rescue_log.push_back( logitem ); +} + + +bool RESCUER::DoRescues() +{ + BOOST_FOREACH( RESCUE_CANDIDATE* each_candidate, m_chosen_candidates ) + { + if( ! each_candidate->PerformAction( this ) ) + return false; + } + return true; +} + + +void RESCUER::UndoRescues() +{ + BOOST_FOREACH( RESCUE_LOG& each_logitem, m_rescue_log ) + { + each_logitem.component->SetPartName( each_logitem.old_name ); + each_logitem.component->ClearFlags(); + } +} + + +wxString RESCUER::GetPartNameSuffix() +{ + wxString suffix = wxT( "-RESCUE-" ); + wxString pname = GetPrj()->GetProjectName(); + for( size_t i = 0; i < pname.Len(); ++i ) + { + if( isspace( pname[i].GetValue() ) ) + suffix.Append( '_' ); + else + suffix.Append( pname[i] ); + } + + return suffix; +} + + +bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand ) +{ + RESCUER rescuer( *this, Prj() ); + + rescuer.FindCandidates(); + + if( ! rescuer.GetCandidateCount() ) + { + if( aRunningOnDemand ) + { + wxMessageDialog dlg( this, _( "This project has nothing to rescue." ) ); + dlg.ShowModal(); + } + return true; + } + + rescuer.RemoveDuplicates(); + + rescuer.InvokeDialog( !aRunningOnDemand ); + + // If no components were rescued, let the user know what's going on. He might + // have clicked cancel by mistake, and should have some indication of that. + if( !rescuer.GetChosenCandidateCount() ) + { + wxMessageDialog dlg( this, _( "No symbols were rescued." ) ); + dlg.ShowModal(); + + // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at + // this point, due to the reloading of the symbols, so we'll make the save button active. + OnModify(); + return true; + } + + RESCUE_CACHE_CANDIDATE::OpenRescueLibrary(); + + if( !rescuer.DoRescues() ) + { + rescuer.UndoRescues(); + return false; + } + + RESCUE_CACHE_CANDIDATE::WriteRescueLibrary( this, &Prj() ); + + Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL ); + + // Clean up wire ends + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + GetScreen()->SchematicCleanUp( NULL, &dc ); + m_canvas->Refresh( true ); + OnModify(); + + return true; +} diff --git a/eeschema/project_rescue.h b/eeschema/project_rescue.h new file mode 100644 index 00000000..4ba538f3 --- /dev/null +++ b/eeschema/project_rescue.h @@ -0,0 +1,198 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Chris Pavlina + * Copyright (C) 2015 KiCad Developers, see change_log.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 _LIB_CACHE_RESCUE_H_ +#define _LIB_CACHE_RESCUE_H_ + +/* This code handles the case where an old schematic was made before + * various changes were made, either to KiCad or to the libraries, and + * the project needs to be recovered. The function of note is a member + * of SCH_EDIT_FRAME, defined thus: + * + * bool SCH_EDIT_FRAME::RescueProject( bool aSilentIfNone ); + * + * When this is called, a list of problematic components is compiled. If + * this list is empty, then the function displays a notification and returns + * (if aSilentIfNone is true, the notification is silenced). + */ + +#include + +#include +#include +#include + +class LIB_PART; +class SCH_COMPONENT; +class RESCUER; + +enum RESCUE_TYPE +{ + RESCUE_CONFLICT, + RESCUE_CASE, +}; + +class RESCUE_CANDIDATE +{ +public: + virtual ~RESCUE_CANDIDATE() {} + + /** + * Function GetRequestedName + * Get the name that was originally requested in the schematic + */ + virtual wxString GetRequestedName() const = 0; + + /** + * Function GetNewName + * Get the name we're proposing changing it to + */ + virtual wxString GetNewName() const = 0; + + /** + * Function GetCacheCandidate + * Get the part that can be loaded from the project cache, if possible, or + * else NULL. + */ + virtual LIB_PART* GetCacheCandidate() const { return NULL; } + + /** + * Function GetLibCandidate + * Get the part the would be loaded from the libraries, if possible, or else + * NULL. + */ + virtual LIB_PART* GetLibCandidate() const { return NULL; } + + /** + * Function GetActionDescription + * Get a description of the action proposed, for displaying in the UI. + */ + virtual wxString GetActionDescription() const = 0; + + /** + * Function PerformAction + * Perform the actual rescue action. If successful, this must log the rescue using + * RESCUER::LogRescue to allow it to be reversed. + * @return True on success. + */ + virtual bool PerformAction( RESCUER* aRescuer ) = 0; +}; + +class RESCUE_LOG +{ +public: + SCH_COMPONENT* component; + wxString old_name; + wxString new_name; +}; + +class RESCUER +{ + friend class DIALOG_RESCUE_EACH; + + std::vector m_components; + PART_LIBS* m_libs; + PROJECT* m_prj; + SCH_EDIT_FRAME* m_edit_frame; + + boost::ptr_vector m_all_candidates; + std::vector m_chosen_candidates; + + std::vector m_rescue_log; + +public: + RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject ); + + /** + * Function FindCandidates + * Populate the RESCUER with all possible candidates. + */ + void FindCandidates(); + + /** + * Function RemoveDuplicates + * Filter out duplicately named rescue candidates. + */ + void RemoveDuplicates(); + + /** + * Function GetCandidateCount + */ + size_t GetCandidateCount() { return m_all_candidates.size(); } + + /** + * Function GetChosenCandidateCount + */ + size_t GetChosenCandidateCount() { return m_chosen_candidates.size(); } + + /** + * Function GetComponents + */ + std::vector* GetComponents() { return &m_components; } + + /** + * Function GetLibs + */ + PART_LIBS* GetLibs() { return m_libs; } + + /** + * Function GetPrj + */ + PROJECT* GetPrj() { return m_prj; } + + /** + * Function GetPartNameSuffix + * Return the suffix to add to rescued parts. + */ + wxString GetPartNameSuffix(); + + /** + * Function InvokeDialog + * Display a dialog to allow the user to select rescues. + * @param aAskShowAgain - whether the "Never Show Again" button should be visible + */ + void InvokeDialog( bool aAskShowAgain ); + + /** + * Function LogRescue + * Used by individual RESCUE_CANDIDATEs to log a rescue for undoing. + */ + void LogRescue( SCH_COMPONENT *aComponent, const wxString& aOldName, + const wxString& aNewName ); + + /** + * Function DoRescues + * Perform all chosen rescue actions, logging them to be undone if necessary. + * @return True on success + */ + bool DoRescues(); + + /** + * Function UndoRescues + * Reverse the effects of all rescues on the project. + */ + void UndoRescues(); +}; + +#endif // _LIB_CACHE_RESCUE_H_ diff --git a/eeschema/protos.h b/eeschema/protos.h new file mode 100644 index 00000000..ae3cf1d0 --- /dev/null +++ b/eeschema/protos.h @@ -0,0 +1,58 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 __PROTOS_H__ +#define __PROTOS_H__ + +#include + +class EDA_DRAW_PANEL; +class PICKED_ITEMS_LIST; +class SCH_ITEM; + + +// operations_on_item_lists.cpp +void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList ); + +/** + * Function DuplicateStruct + * creates a new copy of given struct. + * @param aDrawStruct = the SCH_ITEM to duplicate + * @param aClone (defualt = true) + * if true duplicate also some parameters that must be unique + * (timestamp and sheet name) + * aClone must be false. use true only is undo/redo duplications + */ +SCH_ITEM* DuplicateStruct( SCH_ITEM* DrawStruct, bool aClone = false ); + + +/****************/ +/* EEREDRAW.CPP */ +/****************/ +void DrawDanglingSymbol( EDA_DRAW_PANEL* panel, wxDC* DC, + const wxPoint& pos, EDA_COLOR_T Color ); + + +#endif /* __PROTOS_H__ */ diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp new file mode 100644 index 00000000..52898e82 --- /dev/null +++ b/eeschema/sch_base_frame.cpp @@ -0,0 +1,203 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2015 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include + +// Sttaic members: + + +SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, + FRAME_T aWindowType, const wxString& aTitle, + const wxPoint& aPosition, const wxSize& aSize, long aStyle, + const wxString& aFrameName ) : + EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, + aSize, aStyle, aFrameName ) +{ + m_zoomLevelCoeff = 11.0; // Adjusted to roughly displays zoom level = 1 + // when the screen shows a 1:1 image + // obviously depends on the monitor, + // but this is an acceptable value + m_repeatStep = wxPoint( DEFAULT_REPEAT_OFFSET_X, DEFAULT_REPEAT_OFFSET_Y ); + m_repeatDeltaLabel = DEFAULT_REPEAT_LABEL_INC; +} + + +void SCH_BASE_FRAME::OnOpenLibraryViewer( wxCommandEvent& event ) +{ + LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, true ); + + viewlibFrame->PushPreferences( m_canvas ); + + // On Windows, Raise() does not bring the window on screen, when iconized + if( viewlibFrame->IsIconized() ) + viewlibFrame->Iconize( false ); + + viewlibFrame->Show( true ); + viewlibFrame->Raise(); +} + +// Virtual from EDA_DRAW_FRAME +EDA_COLOR_T SCH_BASE_FRAME::GetDrawBgColor() const +{ + return GetLayerColor( LAYER_BACKGROUND ); +} + +void SCH_BASE_FRAME::SetDrawBgColor( EDA_COLOR_T aColor) +{ + m_drawBgColor= aColor; + SetLayerColor( aColor, LAYER_BACKGROUND ); +} + + +SCH_SCREEN* SCH_BASE_FRAME::GetScreen() const +{ + return (SCH_SCREEN*) EDA_DRAW_FRAME::GetScreen(); +} + +const wxString SCH_BASE_FRAME::GetZoomLevelIndicator() const +{ + return EDA_DRAW_FRAME::GetZoomLevelIndicator(); +} + +void SCH_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings ) +{ + GetScreen()->SetPageSettings( aPageSettings ); +} + + +const PAGE_INFO& SCH_BASE_FRAME::GetPageSettings () const +{ + return GetScreen()->GetPageSettings(); +} + + +const wxSize SCH_BASE_FRAME::GetPageSizeIU() const +{ + // GetSizeIU is compile time dependent: + return GetScreen()->GetPageSettings().GetSizeIU(); +} + + +const wxPoint& SCH_BASE_FRAME::GetAuxOrigin() const +{ + wxASSERT( GetScreen() ); + return GetScreen()->GetAuxOrigin(); +} + + +void SCH_BASE_FRAME::SetAuxOrigin( const wxPoint& aPosition ) +{ + wxASSERT( GetScreen() ); + GetScreen()->SetAuxOrigin( aPosition ); +} + + +const TITLE_BLOCK& SCH_BASE_FRAME::GetTitleBlock() const +{ + wxASSERT( GetScreen() ); + return GetScreen()->GetTitleBlock(); +} + + +void SCH_BASE_FRAME::SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) +{ + wxASSERT( GetScreen() ); + GetScreen()->SetTitleBlock( aTitleBlock ); +} + + +void SCH_BASE_FRAME::UpdateStatusBar() +{ + wxString line; + int dx, dy; + BASE_SCREEN* screen = GetScreen(); + + if( !screen ) + return; + + EDA_DRAW_FRAME::UpdateStatusBar(); + + // Display absolute coordinates: + double dXpos = To_User_Unit( g_UserUnit, GetCrossHairPosition().x ); + double dYpos = To_User_Unit( g_UserUnit, GetCrossHairPosition().y ); + + if ( g_UserUnit == MILLIMETRES ) + { + dXpos = RoundTo0( dXpos, 100.0 ); + dYpos = RoundTo0( dYpos, 100.0 ); + } + + wxString absformatter; + wxString locformatter; + + switch( g_UserUnit ) + { + case INCHES: + absformatter = wxT( "X %.3f Y %.3f" ); + locformatter = wxT( "dx %.3f dy %.3f dist %.3f" ); + break; + + case MILLIMETRES: + absformatter = wxT( "X %.2f Y %.2f" ); + locformatter = wxT( "dx %.2f dy %.2f dist %.2f" ); + break; + + case UNSCALED_UNITS: + absformatter = wxT( "X %f Y %f" ); + locformatter = wxT( "dx %f dy %f dist %f" ); + break; + + case DEGREES: + wxASSERT( false ); + break; + } + + line.Printf( absformatter, dXpos, dYpos ); + SetStatusText( line, 2 ); + + // Display relative coordinates: + dx = GetCrossHairPosition().x - screen->m_O_Curseur.x; + dy = GetCrossHairPosition().y - screen->m_O_Curseur.y; + + dXpos = To_User_Unit( g_UserUnit, dx ); + dYpos = To_User_Unit( g_UserUnit, dy ); + + if( g_UserUnit == MILLIMETRES ) + { + dXpos = RoundTo0( dXpos, 100.0 ); + dYpos = RoundTo0( dYpos, 100.0 ); + } + + // We already decided the formatter above + line.Printf( locformatter, dXpos, dYpos, hypot( dXpos, dYpos ) ); + SetStatusText( line, 3 ); + + // refresh units display + DisplayUnitsMsg(); +} diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h new file mode 100644 index 00000000..c99e1a60 --- /dev/null +++ b/eeschema/sch_base_frame.h @@ -0,0 +1,213 @@ +#ifndef SCH_BASE_FRAME_H_ +#define SCH_BASE_FRAME_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2015 KiCad Developers, see change_log.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 +#include + +class PAGE_INFO; +class TITLE_BLOCK; +class LIB_VIEW_FRAME; +class LIB_EDIT_FRAME; +class LIB_ALIAS; +class PART_LIB; +class SCHLIB_FILTER; + +/** + * Class SCH_BASE_FRAME + * is a shim class between EDA_DRAW_FRAME and several derived classes: + * LIB_EDIT_FRAME, LIB_VIEW_FRAME, and SCH_EDIT_FRAME, and it brings in a + * common way of handling the provided virtual functions for the derived classes. + *

      + * The motivation here is to switch onto GetScreen() for the underlying data model. + * + * @author Dick Hollenbeck + */ +class SCH_BASE_FRAME : public EDA_DRAW_FRAME +{ +protected: + wxPoint m_repeatStep; ///< the increment value of the position of an item + ///< when it is repeated + int m_repeatDeltaLabel; ///< the increment value of labels like bus members + ///< when they are repeated + + +public: + SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, + FRAME_T aWindowType, + const wxString& aTitle, + const wxPoint& aPosition, const wxSize& aSize, + long aStyle, const wxString & aFrameName ); + + SCH_SCREEN* GetScreen() const; // overload EDA_DRAW_FRAME + + /** + * @return the increment value of the position of an item + * for the repeat command + */ + const wxPoint GetRepeatStep() const { return m_repeatStep; } + + /** + * Sets the repeat step value for repeat command + * @param aStep the increment value of the position of an item + * for the repeat command + */ + void SetRepeatStep( const wxPoint& aStep) { m_repeatStep = aStep; } + + /** + * @return the increment value of labels like bus members + * for the repeat command + */ + int GetRepeatDeltaLabel() const { return m_repeatDeltaLabel; } + + /** + * Sets the repeat delta label value for repeat command + * @param aDelta the increment value of labels like bus members + * for the repeat command + */ + void SetRepeatDeltaLabel( int aDelta ) { m_repeatDeltaLabel = aDelta; } + + + /** + * Function GetZoomLevelIndicator + * returns a human readable value which can be displayed as zoom + * level indicator in dialogs. + * Virtual from the base class + */ + const wxString GetZoomLevelIndicator() const; + + void SetPageSettings( const PAGE_INFO& aPageSettings ); // overload EDA_DRAW_FRAME + const PAGE_INFO& GetPageSettings () const; // overload EDA_DRAW_FRAME + const wxSize GetPageSizeIU() const; // overload EDA_DRAW_FRAME + + const wxPoint& GetAuxOrigin() const; // overload EDA_DRAW_FRAME + void SetAuxOrigin( const wxPoint& aPosition ); // overload EDA_DRAW_FRAME + + const wxPoint& GetGridOrigin() const // overload EDA_DRAW_FRAME + { + static wxPoint zero; + return zero; + } + void SetGridOrigin( const wxPoint& aPoint ) {} // overload EDA_DRAW_FRAME + + // Virtual from EDA_DRAW_FRAME + // the background color of the draw canvas: + EDA_COLOR_T GetDrawBgColor() const; + void SetDrawBgColor( EDA_COLOR_T aColor); + + const TITLE_BLOCK& GetTitleBlock() const; // overload EDA_DRAW_FRAME + void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ); // overload EDA_DRAW_FRAME + + void UpdateStatusBar(); // overload EDA_DRAW_FRAME + + /** + * Function SelectComponentFromLib + * Calls the library viewer to select component to import into schematic. + * if the library viewer is currently running, it is closed and reopened + * in modal mode. + * @param aFilter is a SCHLIB_FILTER filter to pass the allowed library names + * and/or the library name to load the component from and/or some other filter + * if NULL, no filtering. + * @param aHistoryList list of previously loaded components + * @param aHistoryLastUnit remembering last unit in last component. + * @param aUseLibBrowser bool to call the library viewer to select the component + * @param aUnit a pointer to int to return the selected unit (if any) + * @param aConvert a pointer to int to return the selected De Morgan shape (if any) + * + * @return the component name + */ + wxString SelectComponentFromLibrary( const SCHLIB_FILTER* aFilter, + wxArrayString& aHistoryList, + int& aHistoryLastUnit, + bool aUseLibBrowser, + int* aUnit, + int* aConvert ); + +protected: + + /** + * Function SelectComponentFromLibBrowser + * Calls the library viewer to select component to import into schematic. + * if the library viewer is currently running, it is closed and reopened + * in modal mode. + * @param aFilter is a filter to pass the allowed library names + * and/or some other filter + * @param aPreselectedAlias Preselected component alias. NULL if none. + * @param aUnit Pointer to Unit-number. Input is the pre-selected unit, output + * is the finally selected unit by the user. Can be NULL. + * @param aConvert Pointer to deMorgan conversion. Input is what is pre-selected, + * output is the finally selected deMorgan type by the user. + * @return the component name + */ + wxString SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFilter, + LIB_ALIAS* aPreselectedAlias, + int* aUnit, int* aConvert ); + + /** + * Function OnOpenLibraryViewer + * Open the library viewer only to browse library contents. + * If the viewed is already opened from this, raise the viewer + * If the viewed is already opened from an other window, close it and reopen + */ + void OnOpenLibraryViewer( wxCommandEvent& event ); + + /** + * Function DisplayComponentsNamesInLib + * Select a component from the list of components in a library + * + * @param aLibrary = a reference to the library to explore + * If NULL the user will be prompted tp chose a library + * @param aBuffer = a wxString to put the selected component name + * + * @return true if a component is selected + * false on cancel + */ + bool DisplayListComponentsInLib( PART_LIB* aLibrary, wxString& aBuffer, + wxString& aPreviousChoice ); + + /** + * Function SelectLibraryFromList + * displays a list of current loaded libraries, and allows the user to select + * a library + * This list is sorted, with the library cache always at end of the list + * @return a reference to the selected library, or NULL + */ + PART_LIB* SelectLibraryFromList(); + + /** + * Function SelectPartNameToLoad + * Select a part name from the list of components (parts) found in a library. + * + * @param aLibrary = a reference to the library to explore + * If NULL the user will be prompted tp chose a library + * @param aBufName = a wxString to put the selected component name + * + * @return true if a component is selected + * false on cancel + */ + bool SelectPartNameToLoad( PART_LIB* aLibrary, wxString& aBufName ); +}; + +#endif // SCH_BASE_FRAME_H_ diff --git a/eeschema/sch_bitmap.cpp b/eeschema/sch_bitmap.cpp new file mode 100644 index 00000000..ce10c614 --- /dev/null +++ b/eeschema/sch_bitmap.cpp @@ -0,0 +1,309 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 jean-pierre.charras + * Copyright (C) 2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_bitmap.cpp + */ + +#include +#include +#include +#include +#include + +#include + + +/* + * class SCH_BITMAP + * This class handle a bitmap image that can be inserted in a schematic. + */ + +SCH_BITMAP::SCH_BITMAP( const wxPoint& pos ) : + SCH_ITEM( NULL, SCH_BITMAP_T ) +{ + m_Pos = pos; + m_Layer = LAYER_NOTES; // used only to draw/plot a rectangle, + // when a bitmap cannot be drawn or plotted + m_Image = new BITMAP_BASE(); +} + + +SCH_BITMAP::SCH_BITMAP( const SCH_BITMAP& aSchBitmap ) : + SCH_ITEM( aSchBitmap ) +{ + m_Pos = aSchBitmap.m_Pos; + m_Layer = aSchBitmap.m_Layer; + m_Image = new BITMAP_BASE( *aSchBitmap.m_Image ); +} + + +SCH_ITEM& SCH_BITMAP::operator=( const SCH_ITEM& aItem ) +{ + wxCHECK_MSG( Type() == aItem.Type(), *this, + wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) + + GetClass() ); + + if( &aItem != this ) + { + SCH_ITEM::operator=( aItem ); + + SCH_BITMAP* bitmap = (SCH_BITMAP*) &aItem; + + delete m_Image; + m_Image = new BITMAP_BASE( *bitmap->m_Image ); + m_Pos = bitmap->m_Pos; + } + + return *this; +} + + +bool SCH_BITMAP::ReadImageFile( const wxString& aFullFilename ) +{ + return m_Image->ReadImageFile( aFullFilename ); +} + + +bool SCH_BITMAP::Save( FILE* aFile ) const +{ + if( fprintf( aFile, "$Bitmap\n" ) == EOF ) + return false; + + if( fprintf( aFile, "Pos %-4d %-4d\n", m_Pos.x, m_Pos.y ) == EOF ) + return false; + + if( fprintf( aFile, "Scale %f\n", m_Image->m_Scale ) == EOF ) + return false; + + if( fprintf( aFile, "Data\n" ) == EOF ) + return false; + + if( !m_Image->SaveData( aFile ) ) + return false; + + if( fprintf( aFile, "\nEndData\n" ) == EOF ) + return false; + + + if( fprintf( aFile, "$EndBitmap\n" ) == EOF ) + return false; + + return true; +} + + +EDA_ITEM* SCH_BITMAP::Clone() const +{ + return new SCH_BITMAP( *this ); +} + + +void SCH_BITMAP::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem->Type() == SCH_BITMAP_T, + wxString::Format( wxT( "SCH_BITMAP object cannot swap data with %s object." ), + GetChars( aItem->GetClass() ) ) ); + + SCH_BITMAP* item = (SCH_BITMAP*) aItem; + std::swap( m_Pos, item->m_Pos ); + std::swap( m_Image, item->m_Image ); +} + + +bool SCH_BITMAP::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char* line = aLine.Line(); + + if( strnicmp( line, "$Bitmap", 7 ) != 0 ) + { + aErrorMsg.Printf( wxT( "Eeschema file bitmap image load error at line %d, aborted" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + for( ; ; ) + { + if( !aLine.ReadLine() ) + return false; + + line = aLine.Line(); + + if( strnicmp( line, "Pos", 3 ) == 0 ) + { + sscanf( line + 3, "%d %d", &m_Pos.x, &m_Pos.y ); + continue; + } + + if( strnicmp( line, "Scale", 5 ) == 0 ) + { + sscanf( line + 5, "%lf", &m_Image->m_Scale ); + continue; + } + + if( strnicmp( line, "Data", 4 ) == 0 ) + { + m_Image->LoadData( aLine, aErrorMsg ); + } + + if( strnicmp( line, "$EndBitmap", 4 ) == 0 ) + break; + } + + return true; +} + + +const EDA_RECT SCH_BITMAP::GetBoundingBox() const +{ + EDA_RECT rect = m_Image->GetBoundingBox(); + + rect.Move( m_Pos ); + + return rect; +} + + +void SCH_BITMAP::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + wxPoint pos = m_Pos + aOffset; + + if( aColor < 0 ) // Use normal drawing function + { + // https://bugs.launchpad.net/kicad/+bug/1529163 + // "Moving images in eeschema on OS X uses + // wrong position and shows image flipped" + // + // Original fix was to only GRSetDrawMode if aColor >= 0, but this made + // moving SCH_BITMAP work poorly on other platforms. +#ifndef __WXMAC__ + GRSetDrawMode( aDC, aDrawMode ); +#endif + + m_Image->DrawBitmap( aPanel, aDC, pos ); + } + else // draws bounding box only (used to move items) + { + GRSetDrawMode( aDC, aDrawMode ); + // To draw the rect, pos is the upper left corner position + wxSize size = m_Image->GetSize(); + pos.x -= size.x / 2; + pos.y -= size.y / 2; + GRRect( aPanel->GetClipBox(), aDC, pos.x, pos.y, + pos.x + size.x, pos.y + size.y, 0, aColor ); + } +} + + +/* Function GetSize + * returns the actual size (in user units, not in pixels) of the image + */ +wxSize SCH_BITMAP::GetSize() const +{ + return m_Image->GetSize(); +} + + +/* + * Mirror image relative to a horizontal X axis ) + */ +void SCH_BITMAP::MirrorX( int aXaxis_position ) +{ + MIRROR( m_Pos.y, aXaxis_position ); + m_Image->Mirror( true ); +} + + +/* + * Mirror image relative to a vertical Y axis + */ +void SCH_BITMAP::MirrorY( int aYaxis_position ) +{ + MIRROR( m_Pos.x, aYaxis_position ); + m_Image->Mirror( false ); +} + + +void SCH_BITMAP::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); + m_Image->Rotate( false ); +} + + +bool SCH_BITMAP::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_Pos ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +#if defined(DEBUG) +void SCH_BITMAP::Show( int nestLevel, std::ostream& os ) const +{ + // XML output: + wxString s = GetClass(); + + NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << m_Pos << "/>\n"; +} + + +#endif + + +bool SCH_BITMAP::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool SCH_BITMAP::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +void SCH_BITMAP::Plot( PLOTTER* aPlotter ) +{ + m_Image->PlotImage( aPlotter, m_Pos, GetLayerColor( GetLayer() ), GetPenSize() ); +} diff --git a/eeschema/sch_bitmap.h b/eeschema/sch_bitmap.h new file mode 100644 index 00000000..27e96e0d --- /dev/null +++ b/eeschema/sch_bitmap.h @@ -0,0 +1,149 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 jean-pierre.charras + * Copyright (C) 2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_bitmap.h + * + */ + +#ifndef _SCH_BITMAP_H_ +#define _SCH_BITMAP_H_ + + +#include +#include + + +class SCH_BITMAP : public SCH_ITEM +{ + wxPoint m_Pos; // XY coordinates of center of the bitmap + +public: + BITMAP_BASE* m_Image; // the BITMAP_BASE item + + +public: + SCH_BITMAP( const wxPoint& pos = wxPoint( 0, 0 ) ); + + SCH_BITMAP( const SCH_BITMAP& aSchBitmap ); + + ~SCH_BITMAP() + { + delete m_Image; + } + + SCH_ITEM& operator=( const SCH_ITEM& aItem ); + + /* + * Accessors: + */ + double GetPixelScaleFactor() { return m_Image->GetPixelScaleFactor(); } + void SetPixelScaleFactor( double aSF ) { m_Image->SetPixelScaleFactor( aSF ); } + + /** + * Function GetScalingFactor + * @return the scaling factor from pixel size to actual draw size + * this scaling factor depend on m_pixelScaleFactor and m_Scale + * m_pixelScaleFactor gives the scaling factor between a pixel size and + * the internal schematic units + * m_Scale is an user dependant value, and gives the "zoom" value + * m_Scale = 1.0 = original size of bitmap. + * m_Scale < 1.0 = the bitmap is drawn smaller than its original size. + * m_Scale > 1.0 = the bitmap is drawn bigger than its original size. + */ + double GetScalingFactor() const + { + return m_Image->GetScalingFactor(); + } + + + wxString GetClass() const + { + return wxT( "SCH_BITMAP" ); + } + + + /** + * Function GetSize + * @returns the actual size (in user units, not in pixels) of the image + */ + wxSize GetSize() const; + + const EDA_RECT GetBoundingBox() const; // Virtual + + void SwapData( SCH_ITEM* aItem ); + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + /** + * Function ReadImageFile + * Reads and stores an image file. Init the bitmap used to draw this item + * format. + * @param aFullFilename The full filename of the image file to read. + * @return bool - true if success reading else false. + */ + bool ReadImageFile( const wxString& aFullFilename ); + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + void Move( const wxPoint& aMoveVector ) + { + m_Pos += aMoveVector; + } + + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool IsSelectStateChanged( const wxRect& aRect ); + + wxString GetSelectMenuText() const { return wxString( _( "Image" ) ); } + + BITMAP_DEF GetMenuImage() const { return image_xpm; } + + wxPoint GetPosition() const { return m_Pos; } + + void SetPosition( const wxPoint& aPosition ) { m_Pos = aPosition; } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif +}; + + +#endif // _SCH_BITMAP_H_ diff --git a/eeschema/sch_bus_entry.cpp b/eeschema/sch_bus_entry.cpp new file mode 100644 index 00000000..9ac88068 --- /dev/null +++ b/eeschema/sch_bus_entry.cpp @@ -0,0 +1,403 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_bus_entry.cpp + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +SCH_BUS_ENTRY_BASE::SCH_BUS_ENTRY_BASE( KICAD_T aType, const wxPoint& pos, char shape ) : + SCH_ITEM( NULL, aType ) +{ + m_pos = pos; + m_size.x = 100; + m_size.y = 100; + + if( shape == '/' ) + m_size.y = -100; + + m_isDanglingStart = m_isDanglingEnd = true; +} + +SCH_BUS_WIRE_ENTRY::SCH_BUS_WIRE_ENTRY( const wxPoint& pos, char shape ) : + SCH_BUS_ENTRY_BASE( SCH_BUS_WIRE_ENTRY_T, pos, shape ) +{ + m_Layer = LAYER_WIRE; +} + +SCH_BUS_BUS_ENTRY::SCH_BUS_BUS_ENTRY( const wxPoint& pos, char shape ) : + SCH_BUS_ENTRY_BASE( SCH_BUS_BUS_ENTRY_T, pos, shape ) +{ + m_Layer = LAYER_BUS; +} + +EDA_ITEM* SCH_BUS_WIRE_ENTRY::Clone() const +{ + return new SCH_BUS_WIRE_ENTRY( *this ); +} + +EDA_ITEM* SCH_BUS_BUS_ENTRY::Clone() const +{ + return new SCH_BUS_BUS_ENTRY( *this ); +} + + +wxPoint SCH_BUS_ENTRY_BASE::m_End() const +{ + return wxPoint( m_pos.x + m_size.x, m_pos.y + m_size.y ); +} + + +void SCH_BUS_ENTRY_BASE::SwapData( SCH_ITEM* aItem ) +{ + SCH_BUS_ENTRY_BASE* item = dynamic_cast( aItem ); + wxCHECK_RET( item, wxT( "Cannot swap bus entry data with invalid item." ) ); + + std::swap( m_pos, item->m_pos ); + std::swap( m_size, item->m_size ); +} + + +bool SCH_BUS_WIRE_ENTRY::Save( FILE* aFile ) const +{ + if( fprintf( aFile, "Entry Wire Line\n\t%-4d %-4d %-4d %-4d\n", + m_pos.x, m_pos.y, m_End().x, m_End().y ) == EOF ) + return false; + return true; +} + + +bool SCH_BUS_BUS_ENTRY::Save( FILE* aFile ) const +{ + if( fprintf( aFile, "Entry Bus Bus\n\t%-4d %-4d %-4d %-4d\n", + m_pos.x, m_pos.y, m_End().x, m_End().y ) == EOF ) + return false; + return true; +} + + +bool SCH_BUS_ENTRY_BASE::Load( LINE_READER& aLine, wxString& aErrorMsg, + SCH_ITEM **out ) +{ + char Name1[256]; + char Name2[256]; + char* line = (char*) aLine; + *out = NULL; + + while( (*line != ' ' ) && *line ) + line++; + + if( sscanf( line, "%255s %255s", Name1, Name2 ) != 2 ) + { + aErrorMsg.Printf( wxT( "Eeschema file bus entry load error at line %d" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + SCH_BUS_ENTRY_BASE *this_new; + if( Name1[0] == 'B' ) + this_new = new SCH_BUS_BUS_ENTRY; + else + this_new = new SCH_BUS_WIRE_ENTRY; + *out = this_new; + + if( !aLine.ReadLine() || sscanf( (char*) aLine, "%d %d %d %d ", + &this_new->m_pos.x, &this_new->m_pos.y, + &this_new->m_size.x, &this_new->m_size.y ) != 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file bus entry load error at line %d" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + this_new->m_size.x -= this_new->m_pos.x; + this_new->m_size.y -= this_new->m_pos.y; + + return true; +} + + +const EDA_RECT SCH_BUS_ENTRY_BASE::GetBoundingBox() const +{ + EDA_RECT box; + + box.SetOrigin( m_pos ); + box.SetEnd( m_End() ); + + box.Normalize(); + box.Inflate( GetPenSize() / 2 ); + + return box; +} + + +int SCH_BUS_WIRE_ENTRY::GetPenSize() const +{ + return GetDefaultLineThickness(); +} + + +int SCH_BUS_BUS_ENTRY::GetPenSize() const +{ + return GetDefaultBusThickness(); +} + + +void SCH_BUS_ENTRY_BASE::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + EDA_COLOR_T color; + EDA_RECT* clipbox = aPanel->GetClipBox(); + + if( aColor >= 0 ) + color = aColor; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( aDC, aDrawMode ); + + GRLine( clipbox, aDC, m_pos.x + aOffset.x, m_pos.y + aOffset.y, + m_End().x + aOffset.x, m_End().y + aOffset.y, GetPenSize(), color ); + + + // Draw pin targets if part is being dragged + bool dragging = aPanel->GetScreen()->GetCurItem() == this && aPanel->IsMouseCaptured(); + + if( m_isDanglingStart || dragging ) + { + GRCircle( clipbox, aDC, m_pos.x + aOffset.x, m_pos.y + aOffset.y, + TARGET_BUSENTRY_RADIUS, 0, color ); + } + + if( m_isDanglingEnd || dragging ) + { + GRCircle( clipbox, aDC, m_End().x + aOffset.x, m_End().y + aOffset.y, + TARGET_BUSENTRY_RADIUS, 0, color ); + } +} + + +void SCH_BUS_ENTRY_BASE::MirrorX( int aXaxis_position ) +{ + MIRROR( m_pos.y, aXaxis_position ); + m_size.y = -m_size.y; +} + + +void SCH_BUS_ENTRY_BASE::MirrorY( int aYaxis_position ) +{ + MIRROR( m_pos.x, aYaxis_position ); + m_size.x = -m_size.x; +} + + +void SCH_BUS_ENTRY_BASE::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_pos, aPosition, 900 ); + RotatePoint( &m_size.x, &m_size.y, 900 ); +} + + +void SCH_BUS_ENTRY_BASE::GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) +{ + DANGLING_END_ITEM item( ENTRY_END, this, m_pos ); + aItemList.push_back( item ); + + DANGLING_END_ITEM item1( ENTRY_END, this, m_End() ); + aItemList.push_back( item1 ); +} + + +bool SCH_BUS_ENTRY_BASE::IsDanglingStateChanged( std::vector& aItemList ) +{ + bool previousStateStart = m_isDanglingStart; + bool previousStateEnd = m_isDanglingEnd; + + m_isDanglingStart = m_isDanglingEnd = true; + + // Wires and buses are stored in the list as a pair, start and end. This + // variable holds the start position from one iteration so it can be used + // when the end position is found. + wxPoint seg_start; + + // Special case: if both items are wires, show as dangling. This is because + // a bus entry between two wires will look like a connection, but does NOT + // actually represent one. We need to clarify this for the user. + bool start_is_wire = false; + bool end_is_wire = false; + + BOOST_FOREACH( DANGLING_END_ITEM& each_item, aItemList ) + { + if( each_item.GetItem() == this ) + continue; + + switch( each_item.GetType() ) + { + case WIRE_START_END: + case BUS_START_END: + seg_start = each_item.GetPosition(); + break; + + case WIRE_END_END: + if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_pos ) ) + start_is_wire = true; + if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_End() ) ) + end_is_wire = true; + // Fall through + + case BUS_END_END: + if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_pos ) ) + m_isDanglingStart = false; + if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_End() ) ) + m_isDanglingEnd = false; + break; + default: + break; + } + } + + // See above: show as dangling if joining two wires + if( start_is_wire && end_is_wire ) + m_isDanglingStart = m_isDanglingEnd = true; + + return (previousStateStart != m_isDanglingStart) || (previousStateEnd != m_isDanglingEnd); +} + + +bool SCH_BUS_ENTRY_BASE::IsDangling() const +{ + return m_isDanglingStart || m_isDanglingEnd; +} + + +bool SCH_BUS_ENTRY_BASE::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + // If either end of the bus entry is inside the selection rectangle, the entire + // bus entry is selected. Bus entries have a fixed length and angle. + if( aRect.Contains( m_pos ) || aRect.Contains( m_End() ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_BUS_ENTRY_BASE::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + aPoints.push_back( m_pos ); + aPoints.push_back( m_End() ); +} + + +wxString SCH_BUS_WIRE_ENTRY::GetSelectMenuText() const +{ + return wxString( _( "Bus to Wire Entry" ) ); +} + + +wxString SCH_BUS_BUS_ENTRY::GetSelectMenuText() const +{ + return wxString( _( "Bus to Bus Entry" ) ); +} + + +bool SCH_BUS_ENTRY_BASE::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + return TestSegmentHit( aPosition, m_pos, m_End(), aAccuracy ); +} + + +bool SCH_BUS_ENTRY_BASE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +void SCH_BUS_ENTRY_BASE::Plot( PLOTTER* aPlotter ) +{ + aPlotter->SetCurrentLineWidth( GetPenSize() ); + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + aPlotter->MoveTo( m_pos ); + aPlotter->FinishTo( m_End() ); +} + +/* SetBusEntryShape: + * Set the shape of the bus entry. + * aShape = ascii code '/' or '\' + */ +void SCH_BUS_ENTRY_BASE::SetBusEntryShape( char aShape ) +{ + switch( aShape ) + { + case '\\': + if( m_size.y < 0 ) + m_size.y = -m_size.y; + break; + + case '/': + if( m_size.y > 0 ) + m_size.y = -m_size.y; + break; + } +} + + +/* GetBusEntryShape: + * return the shape of the bus entry, as an ascii code '/' or '\' + */ +char SCH_BUS_ENTRY_BASE::GetBusEntryShape() const +{ + if( GetSize().y < 0 ) + return '/'; + else + return '\\'; +} + diff --git a/eeschema/sch_bus_entry.h b/eeschema/sch_bus_entry.h new file mode 100644 index 00000000..5de14e66 --- /dev/null +++ b/eeschema/sch_bus_entry.h @@ -0,0 +1,185 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_bus_entry.h + * + */ + +#ifndef _SCH_BUS_ENTRY_H_ +#define _SCH_BUS_ENTRY_H_ + +#include + +#define TARGET_BUSENTRY_RADIUS 12 // Circle diameter drawn at the ends + + +/** + * Class SCH_BUS_ENTRY_BASE + * + * Base class for a bus or wire entry. + */ +class SCH_BUS_ENTRY_BASE : public SCH_ITEM +{ +protected: + wxPoint m_pos; + wxSize m_size; + bool m_isDanglingStart, m_isDanglingEnd; + +public: + SCH_BUS_ENTRY_BASE( KICAD_T aType, const wxPoint& pos = wxPoint( 0, 0 ), char shape = '\\' ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_BUS_ENTRY_BASE() { } + + /** + * Virtual function IsMovableFromAnchorPoint + * Return true for items which are moved with the anchor point at mouse cursor + * and false for items moved with no reference to anchor + * @return false for a bus entry + */ + bool IsMovableFromAnchorPoint() { return false; } + + wxPoint m_End() const; + + /** + * function GetBusEntryShape + * @return the shape of the bus entry, as an ascii code '/' or '\' + */ + char GetBusEntryShape() const; + + /** + * function SetBusEntryShape + * @param aShape = the shape of the bus entry, as an ascii code '/' or '\' + */ + void SetBusEntryShape( char aShape ); + + wxSize GetSize() const { return m_size; } + + void SetSize( const wxSize& aSize ) { m_size = aSize; } + + void SwapData( SCH_ITEM* aItem ); + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + static bool Load( LINE_READER& aLine, wxString& aErrorMsg, SCH_ITEM **out ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + void Move( const wxPoint& aMoveVector ) + { + m_pos += aMoveVector; + } + + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + void GetEndPoints( std::vector & aItemList ); + + bool IsDanglingStateChanged( std::vector& aItemList ); + + bool IsDangling() const; + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const { return true; } + + void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const; + + BITMAP_DEF GetMenuImage() const { return add_entry_xpm; } + + wxPoint GetPosition() const { return m_pos; } + + void SetPosition( const wxPoint& aPosition ) { m_pos = aPosition; } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif +}; + +/** + * Class SCH_BUS_WIRE_ENTRY + * + * Class for a wire to bus entry. + */ +class SCH_BUS_WIRE_ENTRY : public SCH_BUS_ENTRY_BASE +{ +public: + SCH_BUS_WIRE_ENTRY( const wxPoint& pos = wxPoint( 0, 0 ), char shape = '\\' ); + + ~SCH_BUS_WIRE_ENTRY() { } + + wxString GetClass() const + { + return wxT( "SCH_BUS_WIRE_ENTRY" ); + } + + bool Save( FILE* aFile ) const; + + int GetPenSize() const; + + wxString GetSelectMenuText() const; + + EDA_ITEM* Clone() const; +}; + +/** + * Class SCH_BUS_WIRE_ENTRY + * + * Class for a bus to bus entry. + */ +class SCH_BUS_BUS_ENTRY : public SCH_BUS_ENTRY_BASE +{ +public: + SCH_BUS_BUS_ENTRY( const wxPoint& pos = wxPoint( 0, 0 ), char shape = '\\' ); + + ~SCH_BUS_BUS_ENTRY() { } + + wxString GetClass() const + { + return wxT( "SCH_BUS_BUS_ENTRY" ); + } + + bool Save( FILE* aFile ) const; + + int GetPenSize() const; + + wxString GetSelectMenuText() const; + + EDA_ITEM* Clone() const; +}; + +#endif // _SCH_BUS_ENTRY_H_ diff --git a/eeschema/sch_collectors.cpp b/eeschema/sch_collectors.cpp new file mode 100644 index 00000000..04e6b10e --- /dev/null +++ b/eeschema/sch_collectors.cpp @@ -0,0 +1,571 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_collectors.cpp + */ + +#include + +#include +#include +#include +#include +#include +#include + + +const KICAD_T SCH_COLLECTOR::AllItems[] = { + SCH_MARKER_T, + SCH_JUNCTION_T, + SCH_NO_CONNECT_T, + SCH_BUS_BUS_ENTRY_T, + SCH_BUS_WIRE_ENTRY_T, + SCH_LINE_T, + SCH_BITMAP_T, + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_FIELD_T, + SCH_COMPONENT_T, + LIB_PIN_T, + SCH_SHEET_PIN_T, + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::AllItemsButPins[] = { + SCH_MARKER_T, + SCH_JUNCTION_T, + SCH_NO_CONNECT_T, + SCH_BUS_BUS_ENTRY_T, + SCH_BUS_WIRE_ENTRY_T, + SCH_LINE_T, + SCH_BITMAP_T, + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_FIELD_T, + SCH_COMPONENT_T, + SCH_SHEET_PIN_T, + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::EditableItems[] = { + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_FIELD_T, + SCH_COMPONENT_T, + SCH_SHEET_PIN_T, + SCH_SHEET_T, + SCH_BITMAP_T, + EOT +}; + +const KICAD_T SCH_COLLECTOR::CmpFieldValueOnly[] = { + SCH_FIELD_LOCATE_VALUE_T, + EOT +}; + +const KICAD_T SCH_COLLECTOR::CmpFieldReferenceOnly[] = { + SCH_FIELD_LOCATE_REFERENCE_T, + EOT +}; + +const KICAD_T SCH_COLLECTOR::CmpFieldFootprintOnly[] = { + SCH_FIELD_LOCATE_FOOTPRINT_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::MovableItems[] = { + SCH_MARKER_T, + SCH_JUNCTION_T, + SCH_NO_CONNECT_T, + SCH_BUS_BUS_ENTRY_T, + SCH_BUS_WIRE_ENTRY_T, +// SCH_LINE_T, + SCH_BITMAP_T, + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_FIELD_T, + SCH_COMPONENT_T, + SCH_SHEET_PIN_T, + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::DraggableItems[] = { + SCH_JUNCTION_T, + SCH_BUS_BUS_ENTRY_T, + SCH_BUS_WIRE_ENTRY_T, + SCH_LINE_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_COMPONENT_T, + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::RotatableItems[] = { + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_FIELD_T, + SCH_COMPONENT_T, + SCH_SHEET_T, + SCH_BITMAP_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::ParentItems[] = { + SCH_MARKER_T, + SCH_JUNCTION_T, + SCH_NO_CONNECT_T, + SCH_BUS_BUS_ENTRY_T, + SCH_BUS_WIRE_ENTRY_T, + SCH_LINE_T, + SCH_TEXT_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIERARCHICAL_LABEL_T, + SCH_COMPONENT_T, + SCH_SHEET_PIN_T, + SCH_SHEET_T, + SCH_BITMAP_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::ComponentsOnly[] = { + SCH_COMPONENT_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::SheetsOnly[] = { + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::SheetsAndSheetLabels[] = { + SCH_SHEET_PIN_T, + SCH_SHEET_T, + EOT +}; + + +const KICAD_T SCH_COLLECTOR::OrientableItems[] = { + SCH_COMPONENT_T, + SCH_BITMAP_T, + SCH_SHEET_T, + EOT +}; + + +SEARCH_RESULT SCH_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData ) +{ + if( aItem->Type() != LIB_PIN_T && !aItem->HitTest( m_RefPos ) ) + return SEARCH_CONTINUE; + + // Pins have special hit testing requirements that are relative to their parent + // SCH_COMPONENT item. + if( aItem->Type() == LIB_PIN_T ) + { + wxCHECK_MSG( aTestData && ( (EDA_ITEM*) aTestData )->Type() == SCH_COMPONENT_T, + SEARCH_CONTINUE, wxT( "Cannot inspect invalid data. Bad programmer!" ) ); + + // Pin hit testing is relative to the components position and orientation in the + // schematic. The hit test position must be converted to library coordinates. + SCH_COMPONENT* component = (SCH_COMPONENT*) aTestData; + TRANSFORM transform = component->GetTransform().InverseTransform(); + wxPoint position = transform.TransformCoordinate( m_RefPos - component->GetPosition() ); + + position.y *= -1; // Y axis polarity in schematic is inverted from library. + + if( !aItem->HitTest( position ) ) + return SEARCH_CONTINUE; + } + + Append( aItem ); + + return SEARCH_CONTINUE; +} + + +void SCH_COLLECTOR::Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[], + const wxPoint& aPosition ) +{ + Empty(); // empty the collection just in case + + SetScanTypes( aFilterList ); + + // remember where the snapshot was taken from and pass refPos to the Inspect() function. + SetRefPos( aPosition ); + + EDA_ITEM::IterateForward( aItem, this, NULL, m_ScanTypes ); +} + + +bool SCH_COLLECTOR::IsCorner() const +{ + if( GetCount() != 2 ) + return false; + + bool is_busentry0 = (dynamic_cast( m_List[0] ) != NULL); + bool is_busentry1 = (dynamic_cast( m_List[1] ) != NULL); + + if( (m_List[0]->Type() == SCH_LINE_T) && (m_List[1]->Type() == SCH_LINE_T) ) + return true; + + if( (m_List[0]->Type() == SCH_LINE_T) && is_busentry1 ) + return true; + + if( is_busentry0 && (m_List[1]->Type() == SCH_LINE_T) ) + return true; + + return false; +} + + +bool SCH_COLLECTOR::IsNode( bool aIncludePins ) const +{ + for( size_t i = 0; i < m_List.size(); i++ ) + { + SCH_ITEM* item = (SCH_ITEM*) m_List[ i ]; + KICAD_T type = item->Type(); + + if( type == SCH_JUNCTION_T ) + continue; + + if( type == SCH_LINE_T ) + { + if( item->GetLayer() != LAYER_WIRE ) + return false; + + continue; + } + + if( type == LIB_PIN_T ) + { + if( !aIncludePins ) + return false; + + continue; + } + + // Any other item types indicate that this collection is not a node. + return false; + } + + return true; +} + + +bool SCH_COLLECTOR::IsDraggableJunction() const +{ + int wireEndCount = 0; + int wireMidPoint = 0; + int junctionCount = 0; + + for( size_t i = 0; i < m_List.size(); i++ ) + { + SCH_ITEM* item = (SCH_ITEM*) m_List[ i ]; + KICAD_T type = item->Type(); + + if( type == SCH_JUNCTION_T ) + { + junctionCount++; + continue; + } + + if( type == SCH_LINE_T ) + { + if( item->GetLayer() != LAYER_WIRE ) + return false; + + SCH_LINE* line = (SCH_LINE*) item; + + if( line->IsEndPoint( m_RefPos ) ) + wireEndCount++; + else + wireMidPoint++; + + continue; + } + + // Any other item types indicate that this collection is not a draggable junction. + return false; + } + + return (wireEndCount >= 3) || ((wireEndCount >= 1) && (wireMidPoint == 1)) + || ((wireMidPoint >= 2) && (junctionCount == 1)); +} + + +bool SCH_FIND_COLLECTOR::PassedEnd() const +{ + bool retv = false; + + wxUint32 flags = m_findReplaceData.GetFlags(); + + if( GetCount() == 0 ) + return true; + + if( !(flags & FR_SEARCH_WRAP) || (flags & FR_SEARCH_REPLACE) ) + { + if( flags & wxFR_DOWN ) + { + if( m_foundIndex >= GetCount() ) + retv = true; + } + else + { + if( m_foundIndex < 0 ) + retv = true; + } + } + + return retv; +} + + +#if defined(DEBUG) + +void SCH_FIND_COLLECTOR::dump() +{ + int tmp = m_foundIndex; + + wxLogTrace( traceFindReplace, wxT( "%d items found to replace %s with %s." ), + GetCount(), GetChars( m_findReplaceData.GetFindString() ), + GetChars( m_findReplaceData.GetReplaceString() ) ); + + for( m_foundIndex = 0; m_foundIndex < GetCount(); m_foundIndex++ ) + wxLogTrace( traceFindReplace, wxT( " " ) + GetText() ); + + m_foundIndex = tmp; +} + +#endif + + +void SCH_FIND_COLLECTOR::UpdateIndex() +{ + wxUint32 flags = m_findReplaceData.GetFlags(); + + if( flags & wxFR_DOWN ) + { + if( m_foundIndex < GetCount() ) + m_foundIndex += 1; + if( (m_foundIndex >= GetCount()) && (flags & FR_SEARCH_WRAP) ) + m_foundIndex = 0; + } + else + { + if( m_foundIndex >= 0 ) + m_foundIndex -= 1; + if( (m_foundIndex < 0) && (flags & FR_SEARCH_WRAP) ) + m_foundIndex = GetCount() - 1; + } +} + + +SCH_FIND_COLLECTOR_DATA SCH_FIND_COLLECTOR::GetFindData( int aIndex ) +{ + wxCHECK_MSG( (unsigned) aIndex < m_data.size(), SCH_FIND_COLLECTOR_DATA(), + wxT( "Attempt to get find data outside of list boundary." ) ); + + return m_data[ aIndex ]; +} + + +wxString SCH_FIND_COLLECTOR::GetText() +{ + wxCHECK_MSG( (GetCount() != 0) && IsValidIndex( m_foundIndex ), wxEmptyString, + wxT( "Cannot get found item at invalid index." ) ); + + SCH_FIND_COLLECTOR_DATA data = m_data[ m_foundIndex ]; + EDA_ITEM* foundItem = m_List[ m_foundIndex ]; + + wxCHECK_MSG( foundItem != NULL, wxEmptyString, wxT( "Invalid found item pointer." ) ); + + wxString msg; + + if( data.GetParent() ) + { + msg.Printf( _( "Child item %s of parent item %s found in sheet %s" ), + GetChars( foundItem->GetSelectMenuText() ), + GetChars( data.GetParent()->GetSelectMenuText() ), + GetChars( data.GetSheetPath() ) ); + } + else + { + msg.Printf( _( "Item %s found in sheet %s" ), + GetChars( foundItem->GetSelectMenuText() ), + GetChars( data.GetSheetPath() ) ); + } + + return msg; +} + + +EDA_ITEM* SCH_FIND_COLLECTOR::GetItem( SCH_FIND_COLLECTOR_DATA& aData ) +{ + if( PassedEnd() ) + return NULL; + + aData = m_data[ m_foundIndex ]; + return m_List[ m_foundIndex ]; +} + + +bool SCH_FIND_COLLECTOR::ReplaceItem( SCH_SHEET_PATH* aSheetPath ) +{ + if( PassedEnd() ) + return false; + + wxCHECK_MSG( IsValidIndex( m_foundIndex ), false, + wxT( "Invalid replace list index in SCH_FIND_COLLECTOR." ) ); + + EDA_ITEM* item = m_List[ m_foundIndex ]; + + bool replaced = item->Replace( m_findReplaceData, aSheetPath ); + + if( replaced ) + SetForceSearch(); + + return replaced; +} + + +SEARCH_RESULT SCH_FIND_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData ) +{ + wxPoint position; + + if( aItem->Matches( m_findReplaceData, m_sheetPath, &position ) ) + { + if( aItem->Type() == LIB_PIN_T ) + { + wxCHECK_MSG( aTestData && ( (EDA_ITEM*) aTestData )->Type() == SCH_COMPONENT_T, + SEARCH_CONTINUE, wxT( "Cannot inspect invalid data. Bad programmer!" ) ); + + // Pin positions are relative to their parent component's position and + // orientation in the schematic. The pin's position must be converted + // schematic coordinates. + SCH_COMPONENT* component = (SCH_COMPONENT*) aTestData; + TRANSFORM transform = component->GetTransform(); + position.y = -position.y; + position = transform.TransformCoordinate( position ) + component->GetPosition(); + } + + Append( aItem ); + m_data.push_back( SCH_FIND_COLLECTOR_DATA( position, m_sheetPath->PathHumanReadable(), + (SCH_ITEM*) aTestData ) ); + } + + return SEARCH_CONTINUE; +} + + +void SCH_FIND_COLLECTOR::SetReplaceString( const wxString &aReplaceString ) +{ + m_findReplaceData.SetReplaceString( aReplaceString ); +} + + +void SCH_FIND_COLLECTOR::Collect( SCH_FIND_REPLACE_DATA& aFindReplaceData, + SCH_SHEET_PATH* aSheetPath ) +{ + if( !IsSearchRequired( aFindReplaceData ) && !m_List.empty() && !m_forceSearch ) + return; + + m_findReplaceData = aFindReplaceData; + Empty(); // empty the collection just in case + m_data.clear(); + m_foundIndex = 0; + SetForceSearch( false ); + + if( aSheetPath ) + { + m_sheetPath = aSheetPath; + EDA_ITEM::IterateForward( aSheetPath->LastDrawList(), this, NULL, m_ScanTypes ); + } + else + { + SCH_SHEET_LIST schematic; + m_sheetPath = schematic.GetFirst(); + + while( m_sheetPath != NULL ) + { + EDA_ITEM::IterateForward( m_sheetPath->LastDrawList(), this, NULL, m_ScanTypes ); + m_sheetPath = schematic.GetNext(); + } + } + +#if defined(DEBUG) + dump(); +#endif + + if( m_List.size() != m_data.size() ) + { + wxFAIL_MSG( wxT( "List size mismatch." ) ); + m_List.clear(); + m_data.clear(); + } +} + + +SEARCH_RESULT SCH_TYPE_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData ) +{ + // The Vist() function only visits the testItem if its type was in the + // the scanList, so therefore we can collect anything given to us here. + Append( aItem ); + + return SEARCH_CONTINUE; +} + + +void SCH_TYPE_COLLECTOR::Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[] ) +{ + Empty(); // empty the collection + + SetScanTypes( aFilterList ); + + EDA_ITEM::IterateForward( aItem, this, NULL, m_ScanTypes ); +} diff --git a/eeschema/sch_collectors.h b/eeschema/sch_collectors.h new file mode 100644 index 00000000..81f19a54 --- /dev/null +++ b/eeschema/sch_collectors.h @@ -0,0 +1,408 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 2011-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_collectors.h + */ + +#ifndef _SCH_COLLECTORS_H_ +#define _SCH_COLLECTORS_H_ + + +#include +#include +#include + + +/** + * Class SCH_COLLECTOR + */ +class SCH_COLLECTOR : public COLLECTOR +{ +public: + + /** + * A scan list for all schematic items. + */ + static const KICAD_T AllItems[]; + + /** + * A scan list for all editable schematic items. + */ + static const KICAD_T EditableItems[]; + + /** + * A scan list for a specific editable field: Value. + */ + static const KICAD_T CmpFieldValueOnly[]; + + /** + * A scan list for a specific editable field: Reference. + */ + static const KICAD_T CmpFieldReferenceOnly[]; + + /** + * A scan list for a specific editable field: Footprint. + */ + static const KICAD_T CmpFieldFootprintOnly[]; + + /** + * A scan list for all movable schematic items. + */ + static const KICAD_T MovableItems[]; + + /** + * A scan list for all draggable schematic items. + */ + static const KICAD_T DraggableItems[]; + + /** + * A scan list for all rotatable schematic items. + */ + static const KICAD_T RotatableItems[]; + + /** + * A scan list for only parent schematic items. + */ + static const KICAD_T ParentItems[]; + + /** + * A scan list for all schematic items except pins. + */ + static const KICAD_T AllItemsButPins[]; + + /** + * A scan list for schematic component items only. + */ + static const KICAD_T ComponentsOnly[]; + + /** + * A scan list for schematic sheet items only. + */ + static const KICAD_T SheetsOnly[]; + + /** + * A scan list for schematic sheet and sheet label items. + */ + static const KICAD_T SheetsAndSheetLabels[]; + + /** + * A scan list for schematic items that can be mirrored. + */ + static const KICAD_T OrientableItems[]; + + /** + * Constructor SCH_COLLECTOR + */ + SCH_COLLECTOR( const KICAD_T* aScanTypes = SCH_COLLECTOR::AllItems ) + { + SetScanTypes( aScanTypes ); + } + + /** + * Operator [] + * overloads COLLECTOR::operator[](int) to return a SCH_ITEM* instead of + * an EDA_ITEM* type. + * @param aIndex The index into the list. + * @return SCH_ITEM* at \a aIndex or NULL. + */ + SCH_ITEM* operator[]( int aIndex ) const + { + if( (unsigned)aIndex < (unsigned)GetCount() ) + return (SCH_ITEM*) m_List[ aIndex ]; + + return NULL; + } + + SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL ); + + /** + * Function Collect + * scans a SCH_ITEM using this class's Inspector method, which does the collection. + * @param aItem A SCH_ITEM to scan. + * @param aFilterList A list of #KICAD_T types with a terminating #EOT, that determines + * what is to be collected and the priority order of the resulting + * collection. + * @param aPosition A wxPoint to use in hit-testing. + */ + void Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[], const wxPoint& aPosition ); + + /** + * Function IsCorner + * tests if the collected items forms as corner of two line segments. + * @return True if the collected items form a corner of two line segments. + */ + bool IsCorner() const; + + /** + * Function IsNode + * tests if the collected items form a node. + * + * @param aIncludePins Indicate if component pin items should be included in the test. + * @return True if the collected items form a node. + */ + bool IsNode( bool aIncludePins = true ) const; + + /** + * Function IsDraggableJunction + * tests to see if the collected items form a draggable junction. + *

      + * Daggable junctions are defined as: + *

        + *
      • The intersection of three or more wire end points.
      • + *
      • The intersection of one or more wire end point and one wire mid point.
      • + *
      • The crossing of two or more wire mid points and a junction.
      • + *
      + *

      + * @return True if the collection is a draggable junction. + */ + bool IsDraggableJunction() const; +}; + + +/** + * Class SCH_FIND_COLLECTOR_DATA + * is used as a data container for the associated item found by the #SCH_FIND_COLLECTOR + * object. + */ +class SCH_FIND_COLLECTOR_DATA +{ + /// The position in drawing units of the found item. + wxPoint m_position; + + /// The human readable sheet path @see SCH_SHEET_PATH::PathHumanReadable() of the found item. + wxString m_sheetPath; + + /// The parent object if the item found is a child object. + SCH_ITEM* m_parent; + +public: + SCH_FIND_COLLECTOR_DATA( const wxPoint& aPosition = wxDefaultPosition, + const wxString& aSheetPath = wxEmptyString, + SCH_ITEM* aParent = NULL ) + : m_position( aPosition ) + , m_sheetPath( aSheetPath ) + , m_parent( aParent ) + { } + + wxPoint GetPosition() const { return m_position; } + + wxString GetSheetPath() const { return m_sheetPath; } + + SCH_ITEM* GetParent() const { return m_parent; } +}; + + +/** + * Class SCH_FIND_COLLECTOR + * is used to iterate over all of the items in a schematic or sheet and collect all + * the items that match the given search criteria. + */ +class SCH_FIND_COLLECTOR : public COLLECTOR +{ + /// Data associated with each found item. + std::vector< SCH_FIND_COLLECTOR_DATA > m_data; + + /// The criteria used to test for matching items. + SCH_FIND_REPLACE_DATA m_findReplaceData; + + /// The path of the sheet currently being iterated over. + SCH_SHEET_PATH* m_sheetPath; + + /// The current found item list index. + int m_foundIndex; + + /// A flag to indicate that the schemtic has been modified and a new search must be + /// performed even if the search criteria hasn't changed. + bool m_forceSearch; + + /// last known library change hash, used to detect library changes which + /// should trigger cache obsolescence. + int m_lib_hash; + + /** + * Function dump + * is a helper to dump the items in the find list for debugging purposes. + */ +#if defined(DEBUG) + void dump(); +#endif + +public: + + /** + * Constructor SCH_FIND_COLLECTOR + */ + SCH_FIND_COLLECTOR( const KICAD_T* aScanTypes = SCH_COLLECTOR::AllItems ) + { + SetScanTypes( aScanTypes ); + m_foundIndex = 0; + SetForceSearch( false ); + m_sheetPath = NULL; + m_lib_hash = 0; + } + + void Empty() + { + m_foundIndex = 0; + COLLECTOR::Empty(); + m_data.clear(); + } + + void SetForceSearch( bool doSearch = true ) { m_forceSearch = doSearch; } + + int GetLibHash() const { return m_lib_hash; } + void SetLibHash( int aHash ) { m_lib_hash = aHash; } + + int GetFoundIndex() const { return m_foundIndex; } + void SetFoundIndex( int aIndex ) + { + m_foundIndex = ( (unsigned) aIndex < m_data.size() ) ? aIndex : 0; + } + + /** + * Function PassedEnd + * tests if #m_foundIndex is beyond the end of the list give the current + * find/replace criterial in #m_findReplaceData. + * + * @return True if #m_foundIndex has crossed the end of the found item list. + */ + bool PassedEnd() const; + + /** + * Function UpdateIndex + * updates the list index according to the current find and replace criteria. + */ + void UpdateIndex(); + + /** + * Function GetFindData + * returns the data associated with the item found at \a aIndex. + * + * @param aIndex The list index of the data to return. + * @return The associated found item data at \a aIndex if \a aIndex is within the + * list limits. Otherwise an empty data item will be returned. + */ + SCH_FIND_COLLECTOR_DATA GetFindData( int aIndex ); + + /** + * Function IsSearchRequired + * checks the current collector state against \a aFindReplaceData to see if a new search + * needs to be performed to update the collector. + * + * @param aFindReplaceData A #SCH_FIND_REPLACE_DATA object containing the search criteria + * to test for changes against the current search criteria. + * @return True if \a aFindReplaceData would require a new search to be performaed or + * the force search flag is true. Otherwise, false is returned. + */ + bool IsSearchRequired( const SCH_FIND_REPLACE_DATA& aFindReplaceData ) + { + return m_findReplaceData.ChangesCompare( aFindReplaceData ) || m_forceSearch || + (m_findReplaceData.IsWrapping() != aFindReplaceData.IsWrapping()); + } + + /** + * Function GetText() + * @return A wxString object containing the description of the item found at the + * current index or a wxEmptyString if the list is empty or the index is + * invalid. + */ + wxString GetText(); + + /** + * Function GetItem + * returns the item and associated data of the current index. + * + * @param aFindData A reference to a #SCH_FIND_COLLECTOR_DATA object to place the + * associated data for the current item into if the current item + * index is valid. + * @return A pointer to the current #EDA_ITEM in the list if the list index is valid + * Otherwise NULL is returned and the \a aFindData object is not updated. + */ + EDA_ITEM* GetItem( SCH_FIND_COLLECTOR_DATA& aFindData ); + + /** + * Function ReplaceItem + * performs a string replace of the item at the current index. + * + * @return True if the text replace occurred otherwise false. + */ + bool ReplaceItem( SCH_SHEET_PATH* aSheetPath = NULL ); + + SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL ); + + /** + * Update the replace string without changing anything else. + */ + void SetReplaceString( const wxString &aReplaceString ); + + /** + * Function Collect + * scans \a aSheetPath using this class's Inspector method for items matching + * \a aFindReplaceData. + * + * @param aFindReplaceData A #SCH_FIND_REPLACE_DATA object containing the search criteria. + * @param aSheetPath A pointer to a #SCH_SHEET_PATH object to test for matches. A NULL + * value searches the entire schematic hierarchy. + */ + void Collect( SCH_FIND_REPLACE_DATA& aFindReplaceData, SCH_SHEET_PATH* aSheetPath = NULL ); + + void IncrementIndex() { m_foundIndex += 1; } +}; + + +/** + * Class TYPE_COLLECTOR + * merely gathers up all SCH_ITEMs of a given set of KICAD_T type(s). It does + * no hit-testing. + * + * @see class COLLECTOR + */ +class SCH_TYPE_COLLECTOR : public SCH_COLLECTOR +{ +public: + /** + * Function Inspect + * is the examining function within the INSPECTOR which is passed to the + * Iterate function. + * + * @param testItem An EDA_ITEM to examine. + * @param testData is not used in this class. + * @return SEARCH_RESULT - SEARCH_QUIT if the Iterator is to stop the scan, + * else SCAN_CONTINUE; + */ + SEARCH_RESULT Inspect( EDA_ITEM* testItem, const void* testData ); + + /** + * Function Collect + * scans a BOARD_ITEM using this class's Inspector method, which does + * the collection. + * @param aBoard The BOARD_ITEM to scan. + * @param aScanList The KICAD_Ts to gather up. + */ + void Collect( SCH_ITEM* aBoard, const KICAD_T aScanList[] ); +}; + + +#endif // _SCH_COLLECTORS_H_ diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp new file mode 100644 index 00000000..82694d80 --- /dev/null +++ b/eeschema/sch_component.cpp @@ -0,0 +1,2048 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_component.cpp + * @brief Implementation of the class SCH_COMPONENT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include + +#include +#include + +#define NULL_STRING "_NONAME_" + +/** + * Function toUTFTildaText + * convert a wxString to UTF8 and replace any control characters with a ~, + * where a control character is one of the first ASCII values up to ' ' 32d. + */ +static std::string toUTFTildaText( const wxString& txt ) +{ + std::string ret = TO_UTF8( txt ); + + for( std::string::iterator it = ret.begin(); it!=ret.end(); ++it ) + { + if( (unsigned char) *it <= ' ' ) + *it = '~'; + } + return ret; +} + + +/** + * Used when a LIB_PART is not found in library + * to draw a dummy shape + * This component is a 400 mils square with the text ?? + * DEF DUMMY U 0 40 Y Y 1 0 N + * F0 "U" 0 -350 60 H V + * F1 "DUMMY" 0 350 60 H V + * DRAW + * T 0 0 0 150 0 0 0 ?? + * S -200 200 200 -200 0 1 0 + * ENDDRAW + * ENDDEF + */ +static LIB_PART* dummy() +{ + static LIB_PART* part; + + if( !part ) + { + part = new LIB_PART( wxEmptyString ); + + LIB_RECTANGLE* square = new LIB_RECTANGLE( part ); + + square->Move( wxPoint( -200, 200 ) ); + square->SetEndPosition( wxPoint( 200, -200 ) ); + + LIB_TEXT* text = new LIB_TEXT( part ); + + text->SetSize( wxSize( 150, 150 ) ); + text->SetText( wxString( wxT( "??" ) ) ); + + part->AddDrawItem( square ); + part->AddDrawItem( text ); + } + + return part; +} + + +SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos, SCH_ITEM* aParent ) : + SCH_ITEM( aParent, SCH_COMPONENT_T ) +{ + Init( aPos ); + m_currentSheetPath = NULL; +} + + +SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, SCH_SHEET_PATH* sheet, int unit, + int convert, const wxPoint& pos, bool setNewItemFlag ) : + SCH_ITEM( NULL, SCH_COMPONENT_T ) +{ + Init( pos ); + + m_unit = unit; + m_convert = convert; + m_part_name = aPart.GetName(); + m_part = aPart.SharedPtr(); + m_currentSheetPath = NULL; + + SetTimeStamp( GetNewTimeStamp() ); + + if( setNewItemFlag ) + m_Flags = IS_NEW | IS_MOVED; + + // Import user defined fields from the library component: + LIB_FIELDS libFields; + + aPart.GetFields( libFields ); + + for( LIB_FIELDS::iterator it = libFields.begin(); it!=libFields.end(); ++it ) + { + // Can no longer insert an empty name, since names are now keys. The + // field index is not used beyond the first MANDATORY_FIELDS + if( it->GetName().IsEmpty() ) + continue; + + // See if field already exists (mandatory fields always exist). + // for mandatory fields, the name and field id are fixed, so we use the + // known and fixed id to get them (more reliable than names, which can be translated) + // for other fields (custom fields), locate the field by same name + // (field id has no known meaning for custom fields) + int idx = it->GetId(); + SCH_FIELD* schField; + + if( idx < MANDATORY_FIELDS ) + schField = GetField( idx ); + else + schField = FindField( it->GetName() ); + + if( !schField ) + { + SCH_FIELD fld( wxPoint( 0, 0 ), GetFieldCount(), this, it->GetName() ); + schField = AddField( fld ); + } + + schField->SetTextPosition( m_Pos + it->GetTextPosition() ); + schField->ImportValues( *it ); + schField->SetText( it->GetText() ); + } + + wxString msg = aPart.GetReferenceField().GetText(); + + if( msg.IsEmpty() ) + msg = wxT( "U" ); + + m_prefix = msg; + + // update the reference -- just the prefix for now. + msg += wxT( "?" ); + SetRef( sheet, msg ); + + // Use the schematic component name instead of the library value field + // name. + GetField( VALUE )->SetText( GetPartName() ); +} + + +SCH_COMPONENT::SCH_COMPONENT( const SCH_COMPONENT& aComponent ) : + SCH_ITEM( aComponent ) +{ + m_currentSheetPath = NULL; + m_Parent = aComponent.m_Parent; + m_Pos = aComponent.m_Pos; + m_unit = aComponent.m_unit; + m_convert = aComponent.m_convert; + m_part_name = aComponent.m_part_name; + m_part = aComponent.m_part; + + SetTimeStamp( aComponent.m_TimeStamp ); + + m_transform = aComponent.m_transform; + m_prefix = aComponent.m_prefix; + m_PathsAndReferences = aComponent.m_PathsAndReferences; + m_Fields = aComponent.m_Fields; + + // Re-parent the fields, which before this had aComponent as parent + for( int i = 0; iSetParent( this ); + } + + m_isDangling = aComponent.m_isDangling; +} + + +void SCH_COMPONENT::Init( const wxPoint& pos ) +{ + m_Pos = pos; + m_unit = 0; // In multi unit chip - which unit to draw. + m_convert = 0; // De Morgan Handling + + // The rotation/mirror transformation matrix. pos normal + m_transform = TRANSFORM(); + + // construct only the mandatory fields, which are the first 4 only. + for( int i = 0; i < MANDATORY_FIELDS; ++i ) + { + SCH_FIELD field( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) ); + + if( i == REFERENCE ) + field.SetLayer( LAYER_REFERENCEPART ); + else if( i == VALUE ) + field.SetLayer( LAYER_VALUEPART ); + + // else keep LAYER_FIELDS from SCH_FIELD constructor + + // SCH_FIELD's implicitly created copy constructor is called in here + AddField( field ); + } + + m_prefix = wxString( wxT( "U" ) ); +} + + +EDA_ITEM* SCH_COMPONENT::Clone() const +{ + return new SCH_COMPONENT( *this ); +} + + +void SCH_COMPONENT::SetPartName( const wxString& aName, PART_LIBS* aLibs ) +{ + if( m_part_name != aName ) + { + m_part_name = aName; + SetModified(); + + if( aLibs ) + Resolve( aLibs ); + else + m_part.reset(); + } +} + + +bool SCH_COMPONENT::Resolve( PART_LIBS* aLibs ) +{ + // I've never been happy that the actual individual PART_LIB is left up to + // flimsy search path ordering. None-the-less find a part based on that design: + if( LIB_PART* part = aLibs->FindLibPart( m_part_name ) ) + { + m_part = part->SharedPtr(); + return true; + } + + return false; +} + + +void SCH_COMPONENT::ResolveAll( + const SCH_COLLECTOR& aComponents, PART_LIBS* aLibs ) +{ + for( int i = 0; i < aComponents.GetCount(); ++i ) + { + SCH_COMPONENT* cmp = dynamic_cast( aComponents[i] ); + wxASSERT( cmp ); + + if( cmp ) // cmp == NULL should not occur. + cmp->Resolve( aLibs ); + } +} + + +void SCH_COMPONENT::SetUnit( int aUnit ) +{ + if( m_unit != aUnit ) + { + m_unit = aUnit; + SetModified(); + } +} + +void SCH_COMPONENT::UpdateUnit( int aUnit ) +{ + m_unit = aUnit; +} + + +void SCH_COMPONENT::SetConvert( int aConvert ) +{ + if( m_convert != aConvert ) + { + m_convert = aConvert; + SetModified(); + } +} + + +void SCH_COMPONENT::SetTransform( const TRANSFORM& aTransform ) +{ + if( m_transform != aTransform ) + { + m_transform = aTransform; + SetModified(); + } +} + + +int SCH_COMPONENT::GetUnitCount() const +{ + if( PART_SPTR part = m_part.lock() ) + { + return part->GetUnitCount(); + } + + return 0; +} + + +void SCH_COMPONENT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor, + bool aDrawPinText ) +{ + if( PART_SPTR part = m_part.lock() ) + { + // Draw pin targets if part is being dragged + bool dragging = aPanel->GetScreen()->GetCurItem() == this && aPanel->IsMouseCaptured(); + + part->Draw( aPanel, aDC, m_Pos + aOffset, m_unit, m_convert, aDrawMode, aColor, + m_transform, aDrawPinText, false, false, dragging ? NULL : &m_isDangling ); + } + else // Use dummy() part if the actual cannot be found. + { + dummy()->Draw( aPanel, aDC, m_Pos + aOffset, 0, 0, aDrawMode, aColor, + m_transform, aDrawPinText, false ); + } + + SCH_FIELD* field = GetField( REFERENCE ); + + if( field->IsVisible() && !field->IsMoving() ) + { + field->Draw( aPanel, aDC, aOffset, aDrawMode ); + } + + for( int ii = VALUE; ii < GetFieldCount(); ii++ ) + { + field = GetField( ii ); + + if( field->IsMoving() ) + continue; + + field->Draw( aPanel, aDC, aOffset, aDrawMode ); + } + +#if 0 + // Only for testing purposes, draw the component bounding box + { + EDA_RECT boundingBox = GetBoundingBox(); + GRRect( aPanel->GetClipBox(), aDC, boundingBox, 0, BROWN ); +#if 1 + if( GetField( REFERENCE )->IsVisible() ) + { + boundingBox = GetField( REFERENCE )->GetBoundingBox(); + GRRect( aPanel->GetClipBox(), aDC, boundingBox, 0, BROWN ); + } + + if( GetField( VALUE )->IsVisible() ) + { + boundingBox = GetField( VALUE )->GetBoundingBox(); + GRRect( aPanel->GetClipBox(), aDC, boundingBox, 0, BROWN ); + } +#endif + } +#endif +} + + +void SCH_COMPONENT::AddHierarchicalReference( const wxString& aPath, + const wxString& aRef, + int aMulti ) +{ + wxString h_path, h_ref; + wxStringTokenizer tokenizer; + wxString separators( wxT( " " ) ); + + // Search for an existing path and remove it if found (should not occur) + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + tokenizer.SetString( m_PathsAndReferences[ii], separators ); + h_path = tokenizer.GetNextToken(); + + if( h_path.Cmp( aPath ) == 0 ) + { + m_PathsAndReferences.RemoveAt( ii ); + ii--; + } + } + + h_ref = aPath + wxT( " " ) + aRef; + h_ref << wxT( " " ) << aMulti; + m_PathsAndReferences.Add( h_ref ); +} + + +wxString SCH_COMPONENT::GetPath( const SCH_SHEET_PATH* sheet ) const +{ + wxCHECK_MSG( sheet != NULL, wxEmptyString, + wxT( "Cannot get component path with invalid sheet object." ) ); + + wxString str; + + str.Printf( wxT( "%8.8lX" ), (long unsigned) m_TimeStamp ); + return sheet->Path() + str; +} + + +const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet ) +{ + wxString path = GetPath( sheet ); + wxString h_path, h_ref; + wxStringTokenizer tokenizer; + wxString separators( wxT( " " ) ); + + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + tokenizer.SetString( m_PathsAndReferences[ii], separators ); + h_path = tokenizer.GetNextToken(); + + if( h_path.Cmp( path ) == 0 ) + { + h_ref = tokenizer.GetNextToken(); + + /* printf( "GetRef hpath: %s\n", + * TO_UTF8( m_PathsAndReferences[ii] ) ); */ + return h_ref; + } + } + + // if it was not found in m_Paths array, then see if it is in + // m_Field[REFERENCE] -- if so, use this as a default for this path. + // this will happen if we load a version 1 schematic file. + // it will also mean that multiple instances of the same sheet by default + // all have the same component references, but perhaps this is best. + if( !GetField( REFERENCE )->GetText().IsEmpty() ) + { + SetRef( sheet, GetField( REFERENCE )->GetText() ); + return GetField( REFERENCE )->GetText(); + } + + return m_prefix; +} + + +/* Function IsReferenceStringValid (static function) + * Tests for an acceptable reference string + * An acceptable reference string must support unannotation + * i.e starts by letter + * returns true if OK + */ +bool SCH_COMPONENT::IsReferenceStringValid( const wxString& aReferenceString ) +{ + wxString text = aReferenceString; + bool ok = true; + + // Try to unannotate this reference + while( !text.IsEmpty() && ( text.Last() == '?' || isdigit( text.Last() ) ) ) + text.RemoveLast(); + + if( text.IsEmpty() ) + ok = false; + + // Add here other constraints + // Currently:no other constraint + + return ok; +} + + +void SCH_COMPONENT::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref ) +{ + wxString path = GetPath( sheet ); + + bool notInArray = true; + + wxString h_path, h_ref; + wxStringTokenizer tokenizer; + wxString separators( wxT( " " ) ); + + // check to see if it is already there before inserting it + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + tokenizer.SetString( m_PathsAndReferences[ii], separators ); + h_path = tokenizer.GetNextToken(); + + if( h_path.Cmp( path ) == 0 ) + { + // just update the reference text, not the timestamp. + h_ref = h_path + wxT( " " ) + ref; + h_ref += wxT( " " ); + tokenizer.GetNextToken(); // Skip old reference + h_ref += tokenizer.GetNextToken(); // Add part selection + // Ann the part selection + m_PathsAndReferences[ii] = h_ref; + notInArray = false; + } + } + + if( notInArray ) + AddHierarchicalReference( path, ref, m_unit ); + + SCH_FIELD* rf = GetField( REFERENCE ); + + if( rf->GetText().IsEmpty() + || ( abs( rf->GetTextPosition().x - m_Pos.x ) + + abs( rf->GetTextPosition().y - m_Pos.y ) > 10000 ) ) + { + // move it to a reasonable position + rf->SetTextPosition( m_Pos + wxPoint( 50, 50 ) ); + } + + rf->SetText( ref ); // for drawing. + + // Reinit the m_prefix member if needed + wxString prefix = ref; + + if( IsReferenceStringValid( prefix ) ) + { + while( prefix.Last() == '?' || isdigit( prefix.Last() ) ) + prefix.RemoveLast(); + } + else + { + prefix = wxT( "U" ); // Set to default ref prefix + } + + if( m_prefix != prefix ) + m_prefix = prefix; +} + + +void SCH_COMPONENT::SetTimeStamp( time_t aNewTimeStamp ) +{ + wxString string_timestamp, string_oldtimestamp; + + string_timestamp.Printf( wxT( "%08lX" ), (long unsigned) aNewTimeStamp ); + string_oldtimestamp.Printf( wxT( "%08lX" ), (long unsigned) m_TimeStamp ); + EDA_ITEM::SetTimeStamp( aNewTimeStamp ); + + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + m_PathsAndReferences[ii].Replace( string_oldtimestamp.GetData(), + string_timestamp.GetData() ); + } +} + + +int SCH_COMPONENT::GetUnitSelection( SCH_SHEET_PATH* aSheet ) +{ + wxString path = GetPath( aSheet ); + wxString h_path, h_multi; + wxStringTokenizer tokenizer; + wxString separators( wxT( " " ) ); + + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + tokenizer.SetString( m_PathsAndReferences[ii], separators ); + h_path = tokenizer.GetNextToken(); + + if( h_path.Cmp( path ) == 0 ) + { + tokenizer.GetNextToken(); // Skip reference + h_multi = tokenizer.GetNextToken(); + long imulti = 1; + h_multi.ToLong( &imulti ); + return imulti; + } + } + + // if it was not found in m_Paths array, then use m_unit. + // this will happen if we load a version 1 schematic file. + return m_unit; +} + + +void SCH_COMPONENT::SetUnitSelection( SCH_SHEET_PATH* aSheet, int aUnitSelection ) +{ + wxString path = GetPath( aSheet ); + + bool notInArray = true; + + wxString h_path, h_ref; + wxStringTokenizer tokenizer; + wxString separators( wxT( " " ) ); + + //check to see if it is already there before inserting it + for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + tokenizer.SetString( m_PathsAndReferences[ii], separators ); + h_path = tokenizer.GetNextToken(); + + if( h_path.Cmp( path ) == 0 ) + { + //just update the unit selection. + h_ref = h_path + wxT( " " ); + h_ref += tokenizer.GetNextToken(); // Add reference + h_ref += wxT( " " ); + h_ref << aUnitSelection; // Add part selection + + // Ann the part selection + m_PathsAndReferences[ii] = h_ref; + notInArray = false; + } + } + + if( notInArray ) + AddHierarchicalReference( path, m_prefix, aUnitSelection ); +} + + +SCH_FIELD* SCH_COMPONENT::GetField( int aFieldNdx ) const +{ + const SCH_FIELD* field; + + if( (unsigned) aFieldNdx < m_Fields.size() ) + field = &m_Fields[aFieldNdx]; + else + field = NULL; + + wxASSERT( field ); + + // use cast to remove const-ness + return (SCH_FIELD*) field; +} + + +SCH_FIELD* SCH_COMPONENT::AddField( const SCH_FIELD& aField ) +{ + int newNdx = m_Fields.size(); + + m_Fields.push_back( aField ); + return &m_Fields[newNdx]; +} + + +SCH_FIELD* SCH_COMPONENT::FindField( const wxString& aFieldName ) +{ + for( unsigned i = 0; iGetPin( number, m_unit, m_convert ); + } + return NULL; +} + + +void SCH_COMPONENT::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T), + wxT( "Cannot swap data with invalid component." ) ); + + SCH_COMPONENT* component = (SCH_COMPONENT*) aItem; + + std::swap( m_part_name, component->m_part_name ); + std::swap( m_part, component->m_part ); + std::swap( m_Pos, component->m_Pos ); + std::swap( m_unit, component->m_unit ); + std::swap( m_convert, component->m_convert ); + + TRANSFORM tmp = m_transform; + + m_transform = component->m_transform; + component->m_transform = tmp; + + m_Fields.swap( component->m_Fields ); // std::vector's swap() + + // Reparent items after copying data + // (after swap(), m_Parent member does not point to the right parent): + for( int ii = 0; ii < component->GetFieldCount(); ++ii ) + { + component->GetField( ii )->SetParent( component ); + } + + for( int ii = 0; ii < GetFieldCount(); ++ii ) + { + GetField( ii )->SetParent( this ); + } + + std::swap( m_PathsAndReferences, component->m_PathsAndReferences ); +} + + +void SCH_COMPONENT::ClearAnnotation( SCH_SHEET_PATH* aSheetPath ) +{ + bool keepMulti = false; + wxArrayString reference_fields; + + static const wxChar separators[] = wxT( " " ); + + PART_SPTR part = m_part.lock(); + + if( part && part->UnitsLocked() ) + keepMulti = true; + + // Build a reference with no annotation, + // i.e. a reference ended by only one '?' + wxString defRef = m_prefix; + + if( IsReferenceStringValid( defRef ) ) + { + while( defRef.Last() == '?' ) + defRef.RemoveLast(); + } + else + { // This is a malformed reference: reinit this reference + m_prefix = defRef = wxT("U"); // Set to default ref prefix + } + + defRef.Append( wxT( "?" ) ); + + wxString multi = wxT( "1" ); + + // For components with units locked, + // we cannot remove all annotations: part selection must be kept + // For all components: if aSheetPath is not NULL, + // remove annotation only for the given path + if( keepMulti || aSheetPath ) + { + wxString NewHref; + wxString path; + + if( aSheetPath ) + path = GetPath( aSheetPath ); + + for( unsigned int ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + // Break hierarchical reference in path, ref and multi selection: + reference_fields = wxStringTokenize( m_PathsAndReferences[ii], separators ); + + if( aSheetPath == NULL || reference_fields[0].Cmp( path ) == 0 ) + { + if( keepMulti ) // Get and keep part selection + multi = reference_fields[2]; + + NewHref = reference_fields[0]; + NewHref << wxT( " " ) << defRef << wxT( " " ) << multi; + m_PathsAndReferences[ii] = NewHref; + } + } + } + else + { + // Clear reference strings, but does not free memory because a new annotation + // will reuse it + m_PathsAndReferences.Empty(); + m_unit = 1; + } + + // These 2 changes do not work in complex hierarchy. + // When a clear annotation is made, the calling function must call a + // UpdateAllScreenReferences for the active sheet. + // But this call cannot made here. + m_Fields[REFERENCE].SetText( defRef ); //for drawing. + + SetModified(); +} + + +void SCH_COMPONENT::SetOrientation( int aOrientation ) +{ + TRANSFORM temp = TRANSFORM(); + bool transform = false; + + switch( aOrientation ) + { + case CMP_ORIENT_0: + case CMP_NORMAL: // default transform matrix + m_transform.x1 = 1; + m_transform.y2 = -1; + m_transform.x2 = m_transform.y1 = 0; + break; + + case CMP_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation) + temp.x1 = temp.y2 = 0; + temp.y1 = 1; + temp.x2 = -1; + transform = true; + break; + + case CMP_ROTATE_CLOCKWISE: // Rotate - (incremental rotation) + temp.x1 = temp.y2 = 0; + temp.y1 = -1; + temp.x2 = 1; + transform = true; + break; + + case CMP_MIRROR_Y: // Mirror Y (incremental rotation) + temp.x1 = -1; + temp.y2 = 1; + temp.y1 = temp.x2 = 0; + transform = true; + break; + + case CMP_MIRROR_X: // Mirror X (incremental rotation) + temp.x1 = 1; + temp.y2 = -1; + temp.y1 = temp.x2 = 0; + transform = true; + break; + + case CMP_ORIENT_90: + SetOrientation( CMP_ORIENT_0 ); + SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE ); + break; + + case CMP_ORIENT_180: + SetOrientation( CMP_ORIENT_0 ); + SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE ); + SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE ); + break; + + case CMP_ORIENT_270: + SetOrientation( CMP_ORIENT_0 ); + SetOrientation( CMP_ROTATE_CLOCKWISE ); + break; + + case ( CMP_ORIENT_0 + CMP_MIRROR_X ): + SetOrientation( CMP_ORIENT_0 ); + SetOrientation( CMP_MIRROR_X ); + break; + + case ( CMP_ORIENT_0 + CMP_MIRROR_Y ): + SetOrientation( CMP_ORIENT_0 ); + SetOrientation( CMP_MIRROR_Y ); + break; + + case ( CMP_ORIENT_90 + CMP_MIRROR_X ): + SetOrientation( CMP_ORIENT_90 ); + SetOrientation( CMP_MIRROR_X ); + break; + + case ( CMP_ORIENT_90 + CMP_MIRROR_Y ): + SetOrientation( CMP_ORIENT_90 ); + SetOrientation( CMP_MIRROR_Y ); + break; + + case ( CMP_ORIENT_180 + CMP_MIRROR_X ): + SetOrientation( CMP_ORIENT_180 ); + SetOrientation( CMP_MIRROR_X ); + break; + + case ( CMP_ORIENT_180 + CMP_MIRROR_Y ): + SetOrientation( CMP_ORIENT_180 ); + SetOrientation( CMP_MIRROR_Y ); + break; + + case ( CMP_ORIENT_270 + CMP_MIRROR_X ): + SetOrientation( CMP_ORIENT_270 ); + SetOrientation( CMP_MIRROR_X ); + break; + + case ( CMP_ORIENT_270 + CMP_MIRROR_Y ): + SetOrientation( CMP_ORIENT_270 ); + SetOrientation( CMP_MIRROR_Y ); + break; + + default: + transform = false; + wxMessageBox( wxT( "SetRotateMiroir() error: ill value" ) ); + break; + } + + if( transform ) + { + /* The new matrix transform is the old matrix transform modified by the + * requested transformation, which is the temp transform (rot, + * mirror ..) in order to have (in term of matrix transform): + * transform coord = new_m_transform * coord + * where transform coord is the coord modified by new_m_transform from + * the initial value coord. + * new_m_transform is computed (from old_m_transform and temp) to + * have: + * transform coord = old_m_transform * temp + */ + TRANSFORM newTransform; + + newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1; + newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1; + newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2; + newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2; + m_transform = newTransform; + } +} + + +int SCH_COMPONENT::GetOrientation() +{ + int type_rotate = CMP_ORIENT_0; + TRANSFORM transform; + int ii; + + #define ROTATE_VALUES_COUNT 12 + + // list of all possibilities, but only the first 8 are actually used + int rotate_value[ROTATE_VALUES_COUNT] = + { + CMP_ORIENT_0, CMP_ORIENT_90, CMP_ORIENT_180, + CMP_ORIENT_270, + CMP_MIRROR_X + CMP_ORIENT_0, CMP_MIRROR_X + CMP_ORIENT_90, + CMP_MIRROR_X + CMP_ORIENT_180, CMP_MIRROR_X + CMP_ORIENT_270, + CMP_MIRROR_Y + CMP_ORIENT_0, CMP_MIRROR_Y + CMP_ORIENT_90, + CMP_MIRROR_Y + CMP_ORIENT_180, CMP_MIRROR_Y + CMP_ORIENT_270 + }; + + // Try to find the current transform option: + transform = m_transform; + + for( ii = 0; ii < ROTATE_VALUES_COUNT; ii++ ) + { + type_rotate = rotate_value[ii]; + SetOrientation( type_rotate ); + + if( transform == m_transform ) + return type_rotate; + } + + // Error: orientation not found in list (should not happen) + wxMessageBox( wxT( "Component orientation matrix internal error" ) ); + m_transform = transform; + + return CMP_NORMAL; +} + + +wxPoint SCH_COMPONENT::GetScreenCoord( const wxPoint& aPoint ) +{ + return m_transform.TransformCoordinate( aPoint ); +} + + +#if defined(DEBUG) + +void SCH_COMPONENT::Show( int nestLevel, std::ostream& os ) const +{ + // for now, make it look like XML: + NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() + << " ref=\"" << TO_UTF8( GetField( 0 )->GetName() ) + << '"' << " chipName=\"" + << TO_UTF8( GetPartName() ) << '"' << m_Pos + << " layer=\"" << m_Layer + << '"' << ">\n"; + + // skip the reference, it's been output already. + for( int i = 1; i < GetFieldCount(); ++i ) + { + wxString value = GetField( i )->GetText(); + + if( !value.IsEmpty() ) + { + NestedSpace( nestLevel + 1, os ) << "GetName() ) + << '"' << " value=\"" + << TO_UTF8( value ) << "\"/>\n"; + } + } + + NestedSpace( nestLevel, os ) << "\n"; +} + +#endif + + +bool SCH_COMPONENT::Save( FILE* f ) const +{ + std::string name1; + std::string name2; + wxArrayString reference_fields; + + static wxString delimiters( wxT( " " ) ); + + // this is redundant with the AR entries below, but it makes the + // files backwards-compatible. + if( m_PathsAndReferences.GetCount() > 0 ) + { + reference_fields = wxStringTokenize( m_PathsAndReferences[0], delimiters ); + + name1 = toUTFTildaText( reference_fields[1] ); + } + else + { + if( GetField( REFERENCE )->GetText().IsEmpty() ) + name1 = toUTFTildaText( m_prefix ); + else + name1 = toUTFTildaText( GetField( REFERENCE )->GetText() ); + } + + wxString part_name = GetPartName(); + + if( part_name.size() ) + { + name2 = toUTFTildaText( part_name ); + } + else + { + name2 = NULL_STRING; + } + + if( fprintf( f, "$Comp\n" ) == EOF ) + return false; + + if( fprintf( f, "L %s %s\n", name2.c_str(), name1.c_str() ) == EOF ) + return false; + + // Generate unit number, convert and time stamp + if( fprintf( f, "U %d %d %8.8lX\n", m_unit, m_convert, m_TimeStamp ) == EOF ) + return false; + + // Save the position + if( fprintf( f, "P %d %d\n", m_Pos.x, m_Pos.y ) == EOF ) + return false; + + /* If this is a complex hierarchy; save hierarchical references. + * but for simple hierarchies it is not necessary. + * the reference inf is already saved + * this is useful for old Eeschema version compatibility + */ + if( m_PathsAndReferences.GetCount() > 1 ) + { + for( unsigned int ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ ) + { + /*format: + * AR Path="/140/2" Ref="C99" Part="1" + * where 140 is the uid of the containing sheet + * and 2 is the timestamp of this component. + * (timestamps are actually 8 hex chars) + * Ref is the conventional component reference for this 'path' + * Part is the conventional component part selection for this 'path' + */ + reference_fields = wxStringTokenize( m_PathsAndReferences[ii], delimiters ); + + if( fprintf( f, "AR Path=\"%s\" Ref=\"%s\" Part=\"%s\" \n", + TO_UTF8( reference_fields[0] ), + TO_UTF8( reference_fields[1] ), + TO_UTF8( reference_fields[2] ) ) == EOF ) + return false; + } + } + + // update the ugly field index, which I would like to see go away someday soon. + for( unsigned i = 0; iSetId( i ); // we don't need field Ids, please be gone. + } + + // Fixed fields: + // Save mandatory fields even if they are blank, + // because the visibility, size and orientation are set from libary editor. + for( unsigned i = 0; iSave( f ) ) + return false; + } + + // User defined fields: + // The *policy* about which user defined fields are part of a symbol is now + // only in the dialog editors. No policy should be enforced here, simply + // save all the user defined fields, they are present because a dialog editor + // thought they should be. If you disagree, go fix the dialog editors. + for( unsigned i = MANDATORY_FIELDS; iSave( f ) ) + return false; + } + + // Unit number, position, box ( old standard ) + if( fprintf( f, "\t%-4d %-4d %-4d\n", m_unit, m_Pos.x, m_Pos.y ) == EOF ) + return false; + + if( fprintf( f, "\t%-4d %-4d %-4d %-4d\n", + m_transform.x1, m_transform.y1, m_transform.x2, m_transform.y2 ) == EOF ) + return false; + + if( fprintf( f, "$EndComp\n" ) == EOF ) + return false; + + return true; +} + + +bool SCH_COMPONENT::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + // Remark: avoid using sscanf to read texts entered by user + // which are UTF8 encoded, because sscanf does not work well on Windows + // with some UTF8 values. + int ii; + char name1[256], + char1[256], char2[256], char3[256]; + int newfmt = 0; + char* ptcar; + wxString fieldName; + char* line = aLine.Line(); + + m_convert = 1; + + if( line[0] == '$' ) + { + newfmt = 1; + + if( !(line = aLine.ReadLine()) ) + return true; + } + + // Parse the first line of description: + // like "L partname ref" (for instance "L 74LS00 U4" + // They are UTF8 texts, so do not use sscanf + + line += 1; + + if( *line == ' ' ) + line++; + + // line points the first parameter + wxString buffer( FROM_UTF8( line ) ); + wxStringTokenizer tokenizer( buffer, wxT( " \r\n" ) ); + + if( tokenizer.CountTokens() < 2 ) + { + aErrorMsg.Printf( wxT( "Eeschema component description error at line %d, aborted" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( line ); + return false; + } + + wxString partname = tokenizer.NextToken(); + partname.Replace( wxT("~"), wxT(" ") ); // all spaces were replaced by ~ in files. + + if( partname != NULL_STRING ) + { + SetPartName( partname ); + + if( !newfmt ) + GetField( VALUE )->SetText( partname ); + } + else + { + m_part_name.Empty(); + GetField( VALUE )->Empty(); + GetField( VALUE )->SetOrientation( TEXT_ORIENT_HORIZ ); + GetField( VALUE )->SetVisible( false ); + } + + wxString reference = tokenizer.NextToken(); + reference.Replace( wxT("~"), wxT(" ") ); // all spaces were replaced by ~ in files. + reference.Trim( true ); + reference.Trim( false ); + + if( reference != NULL_STRING ) + { + wxString prefix = reference; + // Build reference prefix from the actual reference by removing trailing digits + // (Perhaps outdated code, only for very old schematic files) + while( prefix.Length() ) + { + if( ( prefix.Last() < '0' || prefix.Last() > '9') && prefix.Last() != '?' ) + break; + + prefix.RemoveLast(); + } + + // Avoid a prefix containing trailing/leading spaces + prefix.Trim( true ); + prefix.Trim( false ); + + if( prefix.IsEmpty() ) + m_prefix = wxT( "U" ); + else + m_prefix = prefix; + + if( !newfmt ) + GetField( REFERENCE )->SetText( reference ); + } + else + { + GetField( REFERENCE )->SetVisible( false ); + } + + /* Parse component description + * These lines begin with: + * "P" = Position + * U = Num Unit and Conversion + * "Fn" = Fields (0 .. n = = number of field) + * "Ar" = Alternate reference in the case of multiple sheets referring to + * one schematic file. + */ + for( ; ; ) + { + if( !(line = aLine.ReadLine()) ) + return false; + + if( line[0] == 'U' ) + { + sscanf( line + 1, "%d %d %lX", &m_unit, &m_convert, &m_TimeStamp ); + } + else if( line[0] == 'P' ) + { + sscanf( line + 1, "%d %d", &m_Pos.x, &m_Pos.y ); + + // Set fields position to a default position (that is the + // component position. For existing fields, the real position + // will be set later + for( int i = 0; iGetText().IsEmpty() ) + GetField( i )->SetTextPosition( m_Pos ); + } + } + else if( line[0] == 'A' && line[1] == 'R' ) + { + /* format: + * AR Path="/9086AF6E/67452AA0" Ref="C99" Part="1" + * where 9086AF6E is the unique timestamp of the containing sheet + * and 67452AA0 is the timestamp of this component. + * C99 is the reference given this path. + */ + int ii; + ptcar = line + 2; + + //copy the path. + ii = ReadDelimitedText( name1, ptcar, 255 ); + ptcar += ii + 1; + wxString path = FROM_UTF8( name1 ); + + // copy the reference + ii = ReadDelimitedText( name1, ptcar, 255 ); + ptcar += ii + 1; + wxString ref = FROM_UTF8( name1 ); + + // copy the multi, if exists + ii = ReadDelimitedText( name1, ptcar, 255 ); + + if( name1[0] == 0 ) // Nothing read, put a default value + sprintf( name1, "%d", m_unit ); + + int multi = atoi( name1 ); + + if( multi < 0 || multi > 26 ) + multi = 1; + + AddHierarchicalReference( path, ref, multi ); + GetField( REFERENCE )->SetText( ref ); + } + else if( line[0] == 'F' ) + { + int fieldNdx; + + wxString fieldText; + EDA_TEXT_HJUSTIFY_T hjustify = GR_TEXT_HJUSTIFY_CENTER; + EDA_TEXT_VJUSTIFY_T vjustify = GR_TEXT_VJUSTIFY_CENTER; + + ptcar = (char*) aLine; + + while( *ptcar && (*ptcar != '"') ) + ptcar++; + + if( *ptcar != '"' ) + { + aErrorMsg.Printf( wxT( "Eeschema file library field F at line %d, aborted" ), + aLine.LineNumber() ); + return false; + } + + ptcar += ReadDelimitedText( &fieldText, ptcar ); + + if( *ptcar == 0 ) + { + aErrorMsg.Printf( wxT( "Component field F at line %d, aborted" ), + aLine.LineNumber() ); + return false; + } + + fieldNdx = atoi( line + 2 ); + + ReadDelimitedText( &fieldName, ptcar ); + + if( fieldName.IsEmpty() ) + fieldName = TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldNdx ); + + if( fieldNdx >= GetFieldCount() ) + { + // The first MANDATOR_FIELDS _must_ be constructed within + // the SCH_COMPONENT constructor. This assert is simply here + // to guard against a change in that constructor. + wxASSERT( GetFieldCount() >= MANDATORY_FIELDS ); + + // Ignore the _supplied_ fieldNdx. It is not important anymore + // if within the user defined fields region (i.e. >= MANDATORY_FIELDS). + // We freely renumber the index to fit the next available field slot. + + fieldNdx = GetFieldCount(); // new has this index after insertion + + SCH_FIELD field( wxPoint( 0, 0 ), + -1, // field id is not relavant for user defined fields + this, fieldName ); + + AddField( field ); + } + else + { + GetField( fieldNdx )->SetName( fieldName ); + } + + GetField( fieldNdx )->SetText( fieldText ); + memset( char3, 0, sizeof(char3) ); + int x, y, w, attr; + + if( ( ii = sscanf( ptcar, "%255s %d %d %d %X %255s %255s", char1, &x, &y, &w, &attr, + char2, char3 ) ) < 4 ) + { + aErrorMsg.Printf( wxT( "Component Field error line %d, aborted" ), + aLine.LineNumber() ); + continue; + } + + GetField( fieldNdx )->SetTextPosition( wxPoint( x, y ) ); + GetField( fieldNdx )->SetAttributes( attr ); + + if( (w == 0 ) || (ii == 4) ) + w = GetDefaultTextSize(); + + GetField( fieldNdx )->SetSize( wxSize( w, w ) ); + GetField( fieldNdx )->SetOrientation( TEXT_ORIENT_HORIZ ); + + if( char1[0] == 'V' ) + GetField( fieldNdx )->SetOrientation( TEXT_ORIENT_VERT ); + + if( ii >= 7 ) + { + if( *char2 == 'L' ) + hjustify = GR_TEXT_HJUSTIFY_LEFT; + else if( *char2 == 'R' ) + hjustify = GR_TEXT_HJUSTIFY_RIGHT; + + if( char3[0] == 'B' ) + vjustify = GR_TEXT_VJUSTIFY_BOTTOM; + else if( char3[0] == 'T' ) + vjustify = GR_TEXT_VJUSTIFY_TOP; + + GetField( fieldNdx )->SetItalic( char3[1] == 'I' ); + GetField( fieldNdx )->SetBold( char3[2] == 'B' ); + GetField( fieldNdx )->SetHorizJustify( hjustify ); + GetField( fieldNdx )->SetVertJustify( vjustify ); + } + + if( fieldNdx == REFERENCE ) + if( GetField( fieldNdx )->GetText()[0] == '#' ) + GetField( fieldNdx )->SetVisible( false ); + } + else + { + break; + } + } + + if( sscanf( line, "%d %d %d", &m_unit, &m_Pos.x, &m_Pos.y ) != 3 ) + { + aErrorMsg.Printf( wxT( "Component unit & pos error at line %d, aborted" ), + aLine.LineNumber() ); + return false; + } + + if( !(line = aLine.ReadLine()) || + sscanf( line, "%d %d %d %d", + &m_transform.x1, + &m_transform.y1, + &m_transform.x2, + &m_transform.y2 ) != 4 ) + { + aErrorMsg.Printf( wxT( "Component orient error at line %d, aborted" ), + aLine.LineNumber() ); + return false; + } + + if( newfmt ) + { + if( !(line = aLine.ReadLine()) ) + return false; + + if( strnicmp( "$End", line, 4 ) != 0 ) + { + aErrorMsg.Printf( wxT( "Component End expected at line %d, aborted" ), + aLine.LineNumber() ); + return false; + } + } + + // ensure flags (mainly used in edit) are cleared. + // some changes have set the modified flag + m_Flags = 0; + + return true; +} + + +EDA_RECT SCH_COMPONENT::GetBodyBoundingBox() const +{ + EDA_RECT bBox; + + if( PART_SPTR part = m_part.lock() ) + { + bBox = part->GetBodyBoundingBox( m_unit, m_convert ); + } + else + { + bBox = dummy()->GetBodyBoundingBox( m_unit, m_convert ); + } + + int x0 = bBox.GetX(); + int xm = bBox.GetRight(); + + // We must reverse Y values, because matrix orientation + // suppose Y axis normal for the library items coordinates, + // m_transform reverse Y values, but bBox is already reversed! + int y0 = -bBox.GetY(); + int ym = -bBox.GetBottom(); + + // Compute the real Boundary box (rotated, mirrored ...) + int x1 = m_transform.x1 * x0 + m_transform.y1 * y0; + int y1 = m_transform.x2 * x0 + m_transform.y2 * y0; + int x2 = m_transform.x1 * xm + m_transform.y1 * ym; + int y2 = m_transform.x2 * xm + m_transform.y2 * ym; + + // H and W must be > 0: + if( x2 < x1 ) + std::swap( x2, x1 ); + + if( y2 < y1 ) + std::swap( y2, y1 ); + + bBox.SetX( x1 ); + bBox.SetY( y1 ); + bBox.SetWidth( x2 - x1 ); + bBox.SetHeight( y2 - y1 ); + + bBox.Offset( m_Pos ); + return bBox; +} + + +const EDA_RECT SCH_COMPONENT::GetBoundingBox() const +{ + EDA_RECT bbox = GetBodyBoundingBox(); + + for( size_t i = 0; i < m_Fields.size(); i++ ) + { + bbox.Merge( m_Fields[i].GetBoundingBox() ); + } + + return bbox; +} + + +void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + // part and alias can differ if alias is not the root + if( PART_SPTR part = m_part.lock() ) + { + LIB_ALIAS* alias = part->GetAlias( GetPartName() ); + + if( !alias ) + return; + + if( m_currentSheetPath ) + aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), + GetRef( m_currentSheetPath ), + DARKCYAN ) ); + + wxString msg = part->IsPower() ? _( "Power symbol" ) : _( "Value" ); + + aList.push_back( MSG_PANEL_ITEM( msg, GetField( VALUE )->GetShownText(), DARKCYAN ) ); + + // Display component reference in library and library + aList.push_back( MSG_PANEL_ITEM( _( "Component" ), GetPartName(), BROWN ) ); + + if( alias->GetName() != part->GetName() ) + aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), part->GetName(), BROWN ) ); + + aList.push_back( MSG_PANEL_ITEM( _( "Library" ), alias->GetLibraryName(), BROWN ) ); + + // Display the current associated footprint, if exists. + if( !GetField( FOOTPRINT )->IsVoid() ) + msg = GetField( FOOTPRINT )->GetShownText(); + else + msg = _( "" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Footprint" ), msg, DARKRED ) ); + + // Display description of the component, and keywords found in lib + aList.push_back( MSG_PANEL_ITEM( _( "Description" ), alias->GetDescription(), DARKCYAN ) ); + aList.push_back( MSG_PANEL_ITEM( _( "Key Words" ), alias->GetKeyWords(), DARKCYAN ) ); + } +} + + +void SCH_COMPONENT::MirrorY( int aYaxis_position ) +{ + int dx = m_Pos.x; + + SetOrientation( CMP_MIRROR_Y ); + MIRROR( m_Pos.x, aYaxis_position ); + dx -= m_Pos.x; // dx,0 is the move vector for this transform + + for( int ii = 0; ii < GetFieldCount(); ii++ ) + { + // Move the fields to the new position because the component itself has moved. + wxPoint pos = GetField( ii )->GetTextPosition(); + pos.x -= dx; + GetField( ii )->SetTextPosition( pos ); + } +} + + +void SCH_COMPONENT::MirrorX( int aXaxis_position ) +{ + int dy = m_Pos.y; + + SetOrientation( CMP_MIRROR_X ); + MIRROR( m_Pos.y, aXaxis_position ); + dy -= m_Pos.y; // dy,0 is the move vector for this transform + + for( int ii = 0; ii < GetFieldCount(); ii++ ) + { + // Move the fields to the new position because the component itself has moved. + wxPoint pos = GetField( ii )->GetTextPosition(); + pos.y -= dy; + GetField( ii )->SetTextPosition( pos ); + } +} + + +void SCH_COMPONENT::Rotate( wxPoint aPosition ) +{ + wxPoint prev = m_Pos; + + RotatePoint( &m_Pos, aPosition, 900 ); + + SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE ); + + for( int ii = 0; ii < GetFieldCount(); ii++ ) + { + // Move the fields to the new position because the component itself has moved. + wxPoint pos = GetField( ii )->GetTextPosition(); + pos.x -= prev.x - m_Pos.x; + pos.y -= prev.y - m_Pos.y; + GetField( ii )->SetTextPosition( pos ); + } +} + + +bool SCH_COMPONENT::Matches( wxFindReplaceData& aSearchData, void* aAuxData, + wxPoint* aFindLocation ) +{ + wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText() ); + + // Components are searchable via the child field and pin item text. + return false; +} + + +void SCH_COMPONENT::GetEndPoints( std::vector & aItemList ) +{ + if( PART_SPTR part = m_part.lock() ) + { + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + wxASSERT( pin->Type() == LIB_PIN_T ); + + if( pin->GetUnit() && m_unit && ( m_unit != pin->GetUnit() ) ) + continue; + + if( pin->GetConvert() && m_convert && ( m_convert != pin->GetConvert() ) ) + continue; + + DANGLING_END_ITEM item( PIN_END, pin, GetPinPhysicalPosition( pin ) ); + aItemList.push_back( item ); + } + } +} + + +bool SCH_COMPONENT::IsPinDanglingStateChanged( std::vector &aItemList, + LIB_PINS& aLibPins, unsigned aPin ) +{ + bool previousState; + + if( aPin < m_isDangling.size() ) + { + previousState = m_isDangling[aPin]; + m_isDangling[aPin] = true; + } + else + { + previousState = true; + m_isDangling.push_back( true ); + } + + wxPoint pin_position = GetPinPhysicalPosition( aLibPins[aPin] ); + + BOOST_FOREACH( DANGLING_END_ITEM& each_item, aItemList ) + { + // Some people like to stack pins on top of each other in a symbol to indicate + // internal connection. While technically connected, it is not particularly useful + // to display them that way, so skip any pins that are in the same symbol as this + // one. + // + // Do not make this exception for hidden pins, because those actually make internal + // connections to a power net. + const LIB_PIN* item_pin = dynamic_cast( each_item.GetItem() ); + + if( item_pin + && ( !item_pin->IsPowerConnection() || !IsInNetlist() ) + && std::find( aLibPins.begin(), aLibPins.end(), item_pin) != aLibPins.end() ) + continue; + + switch( each_item.GetType() ) + { + case PIN_END: + case LABEL_END: + case SHEET_LABEL_END: + case WIRE_START_END: + case WIRE_END_END: + case NO_CONNECT_END: + case JUNCTION_END: + if( pin_position == each_item.GetPosition() ) + m_isDangling[aPin] = false; + break; + default: + break; + } + if( !m_isDangling[aPin] ) + break; + } + + return previousState != m_isDangling[aPin]; +} + + +bool SCH_COMPONENT::IsDanglingStateChanged( std::vector& aItemList ) +{ + bool changed = false; + LIB_PINS libPins; + if( PART_SPTR part = m_part.lock() ) + part->GetPins( libPins, m_unit, m_convert ); + for( size_t i = 0; i < libPins.size(); ++i ) + { + if( IsPinDanglingStateChanged( aItemList, libPins, i ) ) + changed = true; + } + return changed; +} + + +bool SCH_COMPONENT::IsDangling() const +{ + BOOST_FOREACH( bool each, m_isDangling ) + { + if( each ) + return true; + } + return false; +} + + +wxPoint SCH_COMPONENT::GetPinPhysicalPosition( LIB_PIN* Pin ) +{ + wxCHECK_MSG( Pin != NULL && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ), + wxT( "Cannot get physical position of pin." ) ); + + return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_Pos; +} + + +bool SCH_COMPONENT::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + EDA_RECT boundingBox = GetBoundingBox(); + + if( aRect.Intersects( boundingBox ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + if( PART_SPTR part = m_part.lock() ) + { + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + wxCHECK_RET( pin->Type() == LIB_PIN_T, + wxT( "GetNextPin() did not return a pin object. Bad programmer!" ) ); + + // Skip items not used for this part. + if( m_unit && pin->GetUnit() && ( pin->GetUnit() != m_unit ) ) + continue; + + if( m_convert && pin->GetConvert() && ( pin->GetConvert() != m_convert ) ) + continue; + + // Calculate the pin position relative to the component position and orientation. + aPoints.push_back( m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos ); + } + } + else + { + wxCHECK_RET( 0, + wxT( "Cannot add connection points to list. Cannot find component <" ) + + GetPartName() + wxT( "> in any of the loaded libraries." ) ); + } +} + + +LIB_ITEM* SCH_COMPONENT::GetDrawItem( const wxPoint& aPosition, KICAD_T aType ) +{ + if( PART_SPTR part = m_part.lock() ) + { + // Calculate the position relative to the component. + wxPoint libPosition = aPosition - m_Pos; + + return part->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform ); + } + + return NULL; +} + + +wxString SCH_COMPONENT::GetSelectMenuText() const +{ + wxString tmp; + tmp.Printf( _( "Component %s, %s" ), + GetChars( GetPartName() ), + GetChars( GetField( REFERENCE )->GetShownText() ) ); + return tmp; +} + + +SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR* aInspector, const void* aTestData, + const KICAD_T aFilterTypes[] ) +{ + KICAD_T stype; + + for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p ) + { + // If caller wants to inspect component type or and component children types. + if( stype == Type() ) + { + if( SEARCH_QUIT == aInspector->Inspect( this, aTestData ) ) + return SEARCH_QUIT; + } + + switch( stype ) + { + case SCH_FIELD_T: + // Test the bounding boxes of fields if they are visible and not empty. + for( int ii = 0; ii < GetFieldCount(); ii++ ) + { + if( SEARCH_QUIT == aInspector->Inspect( GetField( ii ), (void*) this ) ) + return SEARCH_QUIT; + } + break; + + case SCH_FIELD_LOCATE_REFERENCE_T: + if( SEARCH_QUIT == aInspector->Inspect( GetField( REFERENCE ), (void*) this ) ) + return SEARCH_QUIT; + break; + + case SCH_FIELD_LOCATE_VALUE_T: + if( SEARCH_QUIT == aInspector->Inspect( GetField( VALUE ), (void*) this ) ) + return SEARCH_QUIT; + break; + + case SCH_FIELD_LOCATE_FOOTPRINT_T: + if( SEARCH_QUIT == aInspector->Inspect( GetField( FOOTPRINT ), (void*) this ) ) + return SEARCH_QUIT; + break; + + + case LIB_PIN_T: + if( PART_SPTR part = m_part.lock() ) + { + LIB_PINS pins; + + part->GetPins( pins, m_unit, m_convert ); + + for( size_t i = 0; i < pins.size(); i++ ) + { + if( SEARCH_QUIT == aInspector->Inspect( pins[ i ], (void*) this ) ) + return SEARCH_QUIT; + } + } + break; + + default: + break; + } + } + + return SEARCH_CONTINUE; +} + + +void SCH_COMPONENT::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + if( PART_SPTR part = m_part.lock() ) + { + for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + wxASSERT( pin->Type() == LIB_PIN_T ); + + if( pin->GetUnit() && ( pin->GetUnit() != GetUnitSelection( aSheetPath ) ) ) + continue; + + if( pin->GetConvert() && ( pin->GetConvert() != GetConvert() ) ) + continue; + + wxPoint pos = GetTransform().TransformCoordinate( pin->GetPosition() ) + m_Pos; + + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = (SCH_ITEM*) pin; + item->m_SheetPath = *aSheetPath; + item->m_Type = NET_PIN; + item->m_Link = (SCH_ITEM*) this; + item->m_ElectricalType = pin->GetType(); + item->m_PinNum = pin->GetNumber(); + item->m_Label = pin->GetName(); + item->m_Start = item->m_End = pos; + + aNetListItems.push_back( item ); + + if( pin->IsPowerConnection() ) + { + // There is an associated PIN_LABEL. + item = new NETLIST_OBJECT(); + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = NULL; + item->m_SheetPath = *aSheetPath; + item->m_Type = NET_PINLABEL; + item->m_Label = pin->GetName(); + item->m_Start = pos; + item->m_End = item->m_Start; + + aNetListItems.push_back( item ); + } + } + } +} + + +bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const +{ + if( Type() != aItem.Type() ) + return Type() < aItem.Type(); + + SCH_COMPONENT* component = (SCH_COMPONENT*) &aItem; + + EDA_RECT rect = GetBodyBoundingBox(); + + if( rect.GetArea() != component->GetBodyBoundingBox().GetArea() ) + return rect.GetArea() < component->GetBodyBoundingBox().GetArea(); + + if( m_Pos.x != component->m_Pos.x ) + return m_Pos.x < component->m_Pos.x; + + if( m_Pos.y != component->m_Pos.y ) + return m_Pos.y < component->m_Pos.y; + + return false; +} + + +bool SCH_COMPONENT::operator==( const SCH_COMPONENT& aComponent ) const +{ + if( GetFieldCount() != aComponent.GetFieldCount() ) + return false; + + for( int i = VALUE; i < GetFieldCount(); i++ ) + { + if( GetField( i )->GetText().Cmp( aComponent.GetField( i )->GetText() ) != 0 ) + return false; + } + + return true; +} + + +bool SCH_COMPONENT::operator!=( const SCH_COMPONENT& aComponent ) const +{ + return !( *this == aComponent ); +} + + +SCH_ITEM& SCH_COMPONENT::operator=( const SCH_ITEM& aItem ) +{ + wxCHECK_MSG( Type() == aItem.Type(), *this, + wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) + + GetClass() ); + + if( &aItem != this ) + { + SCH_ITEM::operator=( aItem ); + + SCH_COMPONENT* c = (SCH_COMPONENT*) &aItem; + + m_part_name = c->m_part_name; + m_part = c->m_part; + m_Pos = c->m_Pos; + m_unit = c->m_unit; + m_convert = c->m_convert; + m_transform = c->m_transform; + + m_PathsAndReferences = c->m_PathsAndReferences; + + m_Fields = c->m_Fields; // std::vector's assignment operator. + + // Reparent fields after assignment to new component. + for( int ii = 0; ii < GetFieldCount(); ++ii ) + { + GetField( ii )->SetParent( this ); + } + } + + return *this; +} + + +bool SCH_COMPONENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + EDA_RECT bBox = GetBodyBoundingBox(); + bBox.Inflate( aAccuracy ); + + if( bBox.Contains( aPosition ) ) + return true; + + return false; +} + + +bool SCH_COMPONENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + if( m_Flags & STRUCT_DELETED || m_Flags & SKIP_STRUCT ) + return false; + + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBodyBoundingBox() ); + + return rect.Intersects( GetBodyBoundingBox() ); +} + + +bool SCH_COMPONENT::doIsConnected( const wxPoint& aPosition ) const +{ + std::vector< wxPoint > pts; + + GetConnectionPoints( pts ); + + for( size_t i = 0; i < pts.size(); i++ ) + { + if( pts[i] == aPosition ) + return true; + } + + return false; +} + + +bool SCH_COMPONENT::IsInNetlist() const +{ + SCH_FIELD* rf = GetField( REFERENCE ); + return ! rf->GetText().StartsWith( wxT( "#" ) ); +} + + +void SCH_COMPONENT::Plot( PLOTTER* aPlotter ) +{ + TRANSFORM temp; + + if( PART_SPTR part = m_part.lock() ) + { + temp = GetTransform(); + + part->Plot( aPlotter, GetUnit(), GetConvert(), m_Pos, temp ); + + for( size_t i = 0; i < m_Fields.size(); i++ ) + { + m_Fields[i].Plot( aPlotter ); + } + } +} diff --git a/eeschema/sch_component.h b/eeschema/sch_component.h new file mode 100644 index 00000000..8984fc40 --- /dev/null +++ b/eeschema/sch_component.h @@ -0,0 +1,496 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_component.h + * @brief Definition the SCH_COMPONENT class for Eeschema. + */ + +#ifndef COMPONENT_CLASS_H +#define COMPONENT_CLASS_H + + +#include +#include +#include +#include +#include +#include + +class SCH_SHEET_PATH; +class LIB_ITEM; +class LIB_PIN; +class LIB_PART; +class NETLIST_OBJECT_LIST; +class LIB_PART; +class PART_LIBS; +class SCH_COLLECTOR; + + +/// A container for several SCH_FIELD items +typedef std::vector SCH_FIELDS; + +typedef boost::weak_ptr PART_REF; + + +/** + * Class SCH_COMPONENT + * describes a real schematic component + */ +class SCH_COMPONENT : public SCH_ITEM +{ + friend class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC; + + wxPoint m_Pos; + wxString m_part_name; ///< Name to look for in the library, i.e. "74LS00". + + int m_unit; ///< The unit for multiple part per package components. + int m_convert; ///< The alternate body style for components that have more than + ///< one body style defined. Primarily used for components that + ///< have a De Morgan conversion. + wxString m_prefix; ///< C, R, U, Q etc - the first character which typically indicates + ///< what the component is. Determined, upon placement, from the + ///< library component. Created upon file load, by the first + ///< non-digits in the reference fields. + TRANSFORM m_transform; ///< The rotation/mirror transformation matrix. + SCH_FIELDS m_Fields; ///< Variable length list of fields. + + PART_REF m_part; ///< points into the PROJECT's libraries to the LIB_PART for this component + + std::vector m_isDangling; ///< One isDangling per pin + + /** + * A temporary sheet path is required to generate the correct reference designator string + * in complex heirarchies. Hopefully this is only a temporary hack to decouple schematic + * objects from the drawing window until a better design for handling complex heirarchies + * can be implemented. + */ + const SCH_SHEET_PATH* m_currentSheetPath; + + /** + * Defines the hierarchical path and reference of the component. This allows support + * for hierarchical sheets that reference the same schematic. The format for the path + * is /<sheet time stamp>/<sheet time stamp>/.../&lscomponent time stamp>. + * A single / denotes the root sheet. + */ + wxArrayString m_PathsAndReferences; + + void Init( const wxPoint& pos = wxPoint( 0, 0 ) ); + + EDA_RECT GetBodyBoundingBox() const; + +public: + SCH_COMPONENT( const wxPoint& pos = wxPoint( 0, 0 ), SCH_ITEM* aParent = NULL ); + + /** + * Create schematic component from library component object. + * + * @param aPart - library part to create schematic component from. + * @param aSheet - Schematic sheet the component is place into. + * @param unit - Part for components that have multiple parts per + * package. + * @param convert - Use the alternate body style for the schematic + * component. + * @param pos - Position to place new component. + * @param setNewItemFlag - Set the component IS_NEW and IS_MOVED flags. + */ + SCH_COMPONENT( LIB_PART& aPart, SCH_SHEET_PATH* aSheet, + int unit = 0, int convert = 0, + const wxPoint& pos = wxPoint( 0, 0 ), + bool setNewItemFlag = false ); + + /** + * Copy Constructor + * clones \a aComponent into a new object. All fields are copied as is except + * for the linked list management pointers which are set to NULL, and the + * SCH_FIELD's m_Parent pointers which are set to the new parent, + * i.e. this new object. + */ + SCH_COMPONENT( const SCH_COMPONENT& aComponent ); + + ~SCH_COMPONENT() { } + + wxString GetClass() const + { + return wxT( "SCH_COMPONENT" ); + } + + /** + * Virtual function IsMovableFromAnchorPoint + * Return true for items which are moved with the anchor point at mouse cursor + * and false for items moved with no reference to anchor + * Usually return true for small items (labels, junctions) and false for + * items which can be large (hierarchical sheets, compoments) + * @return false for a componant + */ + bool IsMovableFromAnchorPoint() { return false; } + + void SetPartName( const wxString& aName, PART_LIBS* aLibs=NULL ); + const wxString& GetPartName() const { return m_part_name; } + + /** + * Function Resolve + * [re-]assigns the current LIB_PART from aLibs which this component + * is based on. + * @param aLibs is the current set of LIB_PARTs to choose from. + */ + bool Resolve( PART_LIBS* aLibs ); + + static void ResolveAll( const SCH_COLLECTOR& aComponents, PART_LIBS* aLibs ); + + int GetUnit() const { return m_unit; } + + /** + * change the unit id to aUnit + * has maening only for multiple parts per package + * Also set the modified flag bit + * @param aUnit = the new unit Id + */ + void SetUnit( int aUnit ); + + /** + * change the unit id to aUnit + * has maening only for multiple parts per package + * Do not change the modified flag bit, and should be used when + * change is not due to an edition command + * @param aUnit = the new unit Id + */ + void UpdateUnit( int aUnit ); + + int GetConvert() const { return m_convert; } + + void SetConvert( int aConvert ); + + wxString GetPrefix() const { return m_prefix; } + + TRANSFORM& GetTransform() const { return const_cast< TRANSFORM& >( m_transform ); } + + void SetTransform( const TRANSFORM& aTransform ); + + /** + * Function GetUnitCount + * returns the number of parts per package of the component. + * + * @return The number of parts per package or zero if the library entry cannot be found. + */ + int GetUnitCount() const; + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + /** + * Function SetOrientation + * computes the new transform matrix based on \a aOrientation for the component which is + * applied to the current transform. + * @param aOrientation The orientation to apply to the transform. + */ + void SetOrientation( int aOrientation ); + + /** + * Function GetOrientation + * Used to display component orientation (in dialog editor or info) + * @return the orientation and mirror + * Note: Because there are different ways to have a given orientation/mirror, + * the orientation/mirror is not necessary what the used does + * (example : a mirrorX then a mirrorY give no mirror but rotate the + * component). + * So this function find a rotation and a mirror value + * ( CMP_MIRROR_X because this is the first mirror option tested) + * but can differs from the orientation made by an user + * ( a CMP_MIRROR_Y is find as a CMP_MIRROR_X + orientation 180, because + * they are equivalent) + */ + int GetOrientation(); + + /** + * Function GetScreenCoord + * Returns the coordinated point relative to the orientation of the component of \a aPoint. + * The coordinates are always relative to the anchor position of the component. + * @param aPoint The coordinates to transform. + * @return The transformed point. + */ + wxPoint GetScreenCoord( const wxPoint& aPoint ); + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + /** + * Function ClearAnnotation + * clears exiting component annotation ( i.i IC23 changed to IC? and part reset to 1) + * @param aSheetPath: SCH_SHEET_PATH value: if NULL remove all annotations, + * else remove annotation relative to this sheetpath + */ + void ClearAnnotation( SCH_SHEET_PATH* aSheetPath ); + + /** + * Function SetTimeStamp + * changes the time stamp to \a aNewTimeStamp updates the reference path. + * @see m_PathsAndReferences + * @param aNewTimeStamp = new time stamp + */ + void SetTimeStamp( time_t aNewTimeStamp ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + //---------------------------------------------------------------- + + /** + * Function GetField + * returns a field. + * @param aFieldNdx An index into the array of fields, not a field id. + * @return SCH_FIELD* - the field value or NULL if does not exist + */ + SCH_FIELD* GetField( int aFieldNdx ) const; + + /** + * Function AddField + * adds a field to the component. The field is copied as it is put into + * the component. + * @param aField A const reference to the SCH_FIELD to add. + * @return SCH_FIELD* - the newly inserted field. + */ + SCH_FIELD* AddField( const SCH_FIELD& aField ); + + /** + * Function FindField + * searches for SCH_FIELD with \a aFieldName and returns it if found, else NULL. + */ + SCH_FIELD* FindField( const wxString& aFieldName ); + + void SetFields( const SCH_FIELDS& aFields ) + { + m_Fields = aFields; // vector copying, length is changed possibly + } + + //--------------------------------------------------------------- + + /** + * Function GetFieldCount + * returns the number of fields in this component. + */ + int GetFieldCount() const { return (int) m_Fields.size(); } + + /** + * Function GetPin + * finds a component pin by number. + * + * @param number - The number of the pin to find. + * @return Pin object if found, otherwise NULL. + */ + LIB_PIN* GetPin( const wxString& number ); + + /** + * Virtual function, from the base class SCH_ITEM::Draw + */ + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ) + { + Draw( aPanel, aDC, aOffset, aDrawMode, aColor, true ); + } + + /** + * Function Draw, specific to components. + * Draw a component, with or without pin texts. + * @param aPanel DrawPanel to use (can be null) mainly used for clipping purposes. + * @param aDC Device Context (can be null) + * @param aOffset drawing Offset (usually wxPoint(0,0), + * but can be different when moving an object) + * @param aDrawMode GR_OR, GR_XOR, ... + * @param aColor UNSPECIFIED_COLOR to use the normal body item color, or use this color if >= 0 + * @param aDrawPinText = true to draw pin texts, false to draw only the pin shape + * usually false to draw a component when moving it, and true otherwise. + */ + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor, + bool aDrawPinText ); + + void SwapData( SCH_ITEM* aItem ); + + // returns a unique ID, in the form of a path. + wxString GetPath( const SCH_SHEET_PATH* sheet ) const; + + /** + * Function IsReferenceStringValid (static) + * Tests for an acceptable reference string + * An acceptable reference string must support unannotation + * i.e starts by letter + * @param aReferenceString = the reference string to validate + * @return true if OK + */ + static bool IsReferenceStringValid( const wxString& aReferenceString ); + + void SetCurrentSheetPath( const SCH_SHEET_PATH* aSheetPath ) + { + m_currentSheetPath = aSheetPath; + } + + /** + * Function GetRef + * returns the reference, for the given sheet path. + */ + const wxString GetRef( const SCH_SHEET_PATH* sheet ); + + /** + * Set the reference, for the given sheet path. + */ + void SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref ); + + /** + * Function AddHierarchicalReference + * adds a full hierarchical reference (path + local reference) + * @param aPath Hierarchical path (/<sheet timestamp>/<component + * timestamp> like /05678E50/A23EF560) + * @param aRef :local reference like C45, R56 + * @param aMulti Part selection, used in multi part per package (0 or 1 for non multi) + */ + void AddHierarchicalReference( const wxString& aPath, + const wxString& aRef, + int aMulti ); + + // returns the unit selection, for the given sheet path. + int GetUnitSelection( SCH_SHEET_PATH* aSheet ); + + // Set the unit selection, for the given sheet path. + void SetUnitSelection( SCH_SHEET_PATH* aSheet, int aUnitSelection ); + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + if( aMoveVector == wxPoint( 0, 0 ) ) + return; + + m_Pos += aMoveVector; + + for( int ii = 0; ii < GetFieldCount(); ii++ ) + GetField( ii )->Move( aMoveVector ); + + SetModified(); + } + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + void GetEndPoints( std::vector& aItemList ); + + /** + * Test if the component's dangling state has changed for one given pin index. As + * a side effect, actually update the dangling status for that pin. + * + * @param aItemList - list of all DANGLING_END_ITEMs to be tested + * @param aLibPins - list of all the LIB_PIN items in this component's symbol + * @param aPin - index into aLibPins that identifies the pin to test + * @return true if the pin's state has changed. + */ + bool IsPinDanglingStateChanged( std::vector& aItemList, + LIB_PINS& aLibPins, unsigned aPin ); + + /** + * Test if the component's dangling state has changed for all pins. As a side + * effect, actually update the dangling status for all pins (does not short-circuit). + * + * @param aItemList - list of all DANGLING_END_ITEMs to be tested + * @return true if any pin's state has changed. + */ + bool IsDanglingStateChanged( std::vector& aItemList ); + + /** + * Return whether any pin has dangling status. Does NOT update the internal status, + * only checks the existing status. + */ + bool IsDangling() const; + + wxPoint GetPinPhysicalPosition( LIB_PIN* Pin ); + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const { return true; } + + /** + * @return true if the component is in netlist + * which means this is not a power component, or something + * like a component reference starting by # + */ + bool IsInNetlist() const; + + void GetConnectionPoints( std::vector& aPoints ) const; + + SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData, + const KICAD_T scanTypes[] ); + + /** + * Function GetDrawItem(). + * Return the component library item at \a aPosition that is part of this component. + * + * @param aPosition - Schematic position of the component library object. + * @param aType - Type of component library object to find or any if set to TYPE_NOT_INIT. + * @return A pointer to the component library object if found, otherwise NULL. + */ + LIB_ITEM* GetDrawItem( const wxPoint& aPosition, KICAD_T aType = TYPE_NOT_INIT ); + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_component_xpm; } + + void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ); + + bool operator <( const SCH_ITEM& aItem ) const; + + bool operator==( const SCH_COMPONENT& aComponent) const; + bool operator!=( const SCH_COMPONENT& aComponent) const; + + SCH_ITEM& operator=( const SCH_ITEM& aItem ); + + bool IsReplaceable() const { return true; } + + wxPoint GetPosition() const { return m_Pos; } + + void SetPosition( const wxPoint& aPosition ) { Move( aPosition - m_Pos ); } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif + +private: + bool doIsConnected( const wxPoint& aPosition ) const; +}; + + +#endif /* COMPONENT_CLASS_H */ diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp new file mode 100644 index 00000000..46b8834b --- /dev/null +++ b/eeschema/sch_field.cpp @@ -0,0 +1,589 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2014 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_field.cpp + * @brief Implementation of the SCH_FIELD class. + */ + +/* Fields are texts attached to a component, having a special meaning + * Fields 0 and 1 are very important: reference and value + * Field 2 is used as default footprint name. + * Field 3 is reserved (not currently used + * Fields 4 and more are user fields. + * They can be renamed and can appear in reports + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +SCH_FIELD::SCH_FIELD( const wxPoint& aPos, int aFieldId, SCH_COMPONENT* aParent, wxString aName ) : + SCH_ITEM( aParent, SCH_FIELD_T ), + EDA_TEXT() +{ + m_Pos = aPos; + m_id = aFieldId; + m_Attributs = TEXT_NO_VISIBLE; + m_name = aName; + + SetLayer( LAYER_FIELDS ); +} + + +SCH_FIELD::~SCH_FIELD() +{ +} + + +EDA_ITEM* SCH_FIELD::Clone() const +{ + return new SCH_FIELD( *this ); +} + + +const wxString SCH_FIELD::GetFullyQualifiedText() const +{ + wxString text = m_Text; + + /* For more than one part per package, we must add the part selection + * A, B, ... or 1, 2, .. to the reference. */ + if( m_id == REFERENCE ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) m_Parent; + + wxCHECK_MSG( component != NULL, text, + wxT( "No component associated with field" ) + text ); + + if( component->GetUnitCount() > 1 ) + text << LIB_PART::SubReference( component->GetUnit() ); + } + + return text; +} + + +int SCH_FIELD::GetPenSize() const +{ + int pensize = m_Thickness; + + if( pensize == 0 ) // Use default values for pen size + { + if( m_Bold ) + pensize = GetPenSizeForBold( m_Size.x ); + else + pensize = GetDefaultLineThickness(); + } + + // Clip pen size for small texts: + pensize = Clamp_Text_PenSize( pensize, m_Size, m_Bold ); + return pensize; +} + + +void SCH_FIELD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + int orient; + EDA_COLOR_T color; + wxPoint textpos; + SCH_COMPONENT* parentComponent = (SCH_COMPONENT*) m_Parent; + int LineWidth = m_Thickness; + + if( LineWidth == 0 ) // Use default values for pen size + { + if( m_Bold ) + LineWidth = GetPenSizeForBold( m_Size.x ); + else + LineWidth = GetDefaultLineThickness(); + } + + // Clip pen size for small texts: + LineWidth = Clamp_Text_PenSize( LineWidth, m_Size, m_Bold ); + + if( ((m_Attributs & TEXT_NO_VISIBLE) && !m_forceVisible) || IsVoid() ) + return; + + GRSetDrawMode( aDC, aDrawMode ); + + // Calculate the text orientation according to the component orientation. + orient = m_Orient; + + if( parentComponent->GetTransform().y1 ) // Rotate component 90 degrees. + { + if( orient == TEXT_ORIENT_HORIZ ) + orient = TEXT_ORIENT_VERT; + else + orient = TEXT_ORIENT_HORIZ; + } + + /* Calculate the text justification, according to the component + * orientation/mirror this is a bit complicated due to cumulative + * calculations: + * - numerous cases (mirrored or not, rotation) + * - the DrawGraphicText function recalculate also H and H justifications + * according to the text orientation. + * - When a component is mirrored, the text is not mirrored and + * justifications are complicated to calculate + * so the more easily way is to use no justifications ( Centered text ) + * and use GetBoundaryBox to know the text coordinate considered as centered + */ + EDA_RECT boundaryBox = GetBoundingBox(); + textpos = boundaryBox.Centre() + aOffset; + + if( m_forceVisible ) + { + color = DARKGRAY; + } + else + { + if( m_id == REFERENCE ) + color = GetLayerColor( LAYER_REFERENCEPART ); + else if( m_id == VALUE ) + color = GetLayerColor( LAYER_VALUEPART ); + else + color = GetLayerColor( LAYER_FIELDS ); + } + + EDA_RECT* clipbox = aPanel ? aPanel->GetClipBox() : NULL; + DrawGraphicText( clipbox, aDC, textpos, color, GetFullyQualifiedText(), orient, m_Size, + GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, + LineWidth, m_Italic, m_Bold ); + + // While moving: don't loose visual contact to which component this label belongs. + if ( IsWireImage() ) + { + const wxPoint origin = parentComponent->GetPosition(); + textpos = m_Pos - origin; + textpos = parentComponent->GetScreenCoord( textpos ); + textpos += parentComponent->GetPosition(); + GRLine( clipbox, aDC, origin, textpos, 2, DARKGRAY ); + } + + /* Enable this to draw the bounding box around the text field to validate + * the bounding box calculations. + */ +#if 0 + + // Draw boundary box: + GRRect( aPanel->GetClipBox(), aDC, boundaryBox, 0, BROWN ); + + // Draw the text anchor point + + /* Calculate the text position, according to the component + * orientation/mirror */ + textpos = m_Pos - parentComponent->GetPosition(); + textpos = parentComponent->GetScreenCoord( textpos ); + textpos += parentComponent->GetPosition(); + const int len = 10; + GRLine( clipbox, aDC, + textpos.x - len, textpos.y, textpos.x + len, textpos.y, 0, BLUE ); + GRLine( clipbox, aDC, + textpos.x, textpos.y - len, textpos.x, textpos.y + len, 0, BLUE ); +#endif +} + + +void SCH_FIELD::ImportValues( const LIB_FIELD& aSource ) +{ + m_Orient = aSource.GetOrientation(); + m_Size = aSource.GetSize(); + m_HJustify = aSource.GetHorizJustify(); + m_VJustify = aSource.GetVertJustify(); + m_Italic = aSource.IsItalic(); + m_Bold = aSource.IsBold(); + m_Thickness = aSource.GetThickness(); + m_Attributs = aSource.GetAttributes(); + m_Mirror = aSource.IsMirrored(); +} + + +void SCH_FIELD::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_FIELD_T), + wxT( "Cannot swap field data with invalid item." ) ); + + SCH_FIELD* item = (SCH_FIELD*) aItem; + + std::swap( m_Text, item->m_Text ); + std::swap( m_Layer, item->m_Layer ); + std::swap( m_Pos, item->m_Pos ); + std::swap( m_Size, item->m_Size ); + std::swap( m_Thickness, item->m_Thickness ); + std::swap( m_Orient, item->m_Orient ); + std::swap( m_Mirror, item->m_Mirror ); + std::swap( m_Attributs, item->m_Attributs ); + std::swap( m_Italic, item->m_Italic ); + std::swap( m_Bold, item->m_Bold ); + std::swap( m_HJustify, item->m_HJustify ); + std::swap( m_VJustify, item->m_VJustify ); +} + + +const EDA_RECT SCH_FIELD::GetBoundingBox() const +{ + SCH_COMPONENT* parentComponent = (SCH_COMPONENT*) m_Parent; + int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; + + // We must pass the effective text thickness to GetTextBox + // when calculating the bounding box + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + // Calculate the text bounding box: + EDA_RECT rect; + + if( m_id == REFERENCE ) // multi units have one letter or more added to reference + { + SCH_FIELD text( *this ); // Make a local copy to change text + // because GetBoundingBox() is const + text.SetText( GetFullyQualifiedText() ); + rect = text.GetTextBox( -1, linewidth ); + } + else + rect = GetTextBox( -1, linewidth ); + + // Calculate the bounding box position relative to the component: + wxPoint origin = parentComponent->GetPosition(); + wxPoint pos = m_Pos - origin; + wxPoint begin = rect.GetOrigin() - origin; + wxPoint end = rect.GetEnd() - origin; + RotatePoint( &begin, pos, m_Orient ); + RotatePoint( &end, pos, m_Orient ); + + // Due to the Y axis direction, we must mirror the bounding box, + // relative to the text position: + MIRROR( begin.y, pos.y ); + MIRROR( end.y, pos.y ); + + // Now, apply the component transform (mirror/rot) + begin = parentComponent->GetTransform().TransformCoordinate( begin ); + end = parentComponent->GetTransform().TransformCoordinate( end ); + rect.SetOrigin( begin); + rect.SetEnd( end); + rect.Move( origin ); + rect.Normalize(); + return rect; +} + + +bool SCH_FIELD::Save( FILE* aFile ) const +{ + char hjustify = 'C'; + + if( m_HJustify == GR_TEXT_HJUSTIFY_LEFT ) + hjustify = 'L'; + else if( m_HJustify == GR_TEXT_HJUSTIFY_RIGHT ) + hjustify = 'R'; + + char vjustify = 'C'; + + if( m_VJustify == GR_TEXT_VJUSTIFY_BOTTOM ) + vjustify = 'B'; + else if( m_VJustify == GR_TEXT_VJUSTIFY_TOP ) + vjustify = 'T'; + + if( fprintf( aFile, "F %d %s %c %-3d %-3d %-3d %4.4X %c %c%c%c", + m_id, + EscapedUTF8( m_Text ).c_str(), // wraps in quotes too + m_Orient == TEXT_ORIENT_HORIZ ? 'H' : 'V', + m_Pos.x, m_Pos.y, + m_Size.x, + m_Attributs, + hjustify, vjustify, + m_Italic ? 'I' : 'N', + m_Bold ? 'B' : 'N' ) == EOF ) + { + return false; + } + + // Save field name, if the name is user definable + if( m_id >= FIELD1 ) + { + if( fprintf( aFile, " %s", EscapedUTF8( m_name ).c_str() ) == EOF ) + { + return false; + } + } + + if( fprintf( aFile, "\n" ) == EOF ) + { + return false; + } + + return true; +} + + +void SCH_FIELD::Place( SCH_EDIT_FRAME* frame, wxDC* DC ) +{ + frame->GetCanvas()->SetMouseCapture( NULL, NULL ); + + SCH_COMPONENT* component = (SCH_COMPONENT*) GetParent(); + + // save old cmp in undo list + frame->SaveUndoItemInUndoList( component ); + + Draw( frame->GetCanvas(), DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + ClearFlags(); + frame->GetScreen()->SetCurItem( NULL ); + frame->OnModify(); +} + + +bool SCH_FIELD::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ) +{ + bool match; + wxString text = GetFullyQualifiedText(); + + // User defined fields have an ID of -1. + if( ((m_id > VALUE || m_id < REFERENCE) && !(aSearchData.GetFlags() & FR_SEARCH_ALL_FIELDS)) + || ((m_id == REFERENCE) && !(aSearchData.GetFlags() & FR_REPLACE_REFERENCES)) ) + return false; + + wxLogTrace( traceFindItem, wxT( " child item " ) + GetSelectMenuText() ); + + // Take sheet path into account which effects the reference field and the unit for + // components with multiple parts. + if( m_id == REFERENCE && aAuxData != NULL ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) m_Parent; + + wxCHECK_MSG( component != NULL, false, + wxT( "No component associated with field" ) + text ); + + text = component->GetRef( (SCH_SHEET_PATH*) aAuxData ); + + if( component->GetUnitCount() > 1 ) + text << LIB_PART::SubReference( component->GetUnit() ); + } + + match = SCH_ITEM::Matches( text, aSearchData ); + + if( match ) + { + if( aFindLocation ) + *aFindLocation = GetBoundingBox().Centre(); + + return true; + } + + return false; +} + + +bool SCH_FIELD::Replace( wxFindReplaceData& aSearchData, void* aAuxData ) +{ + bool isReplaced; + wxString text = GetFullyQualifiedText(); + + if( m_id == REFERENCE ) + { + wxCHECK_MSG( aAuxData != NULL, false, + wxT( "Cannot replace reference designator without valid sheet path." ) ); + + wxCHECK_MSG( aSearchData.GetFlags() & FR_REPLACE_REFERENCES, false, + wxT( "Invalid replace component reference field call." ) ) ; + + SCH_COMPONENT* component = (SCH_COMPONENT*) m_Parent; + + wxCHECK_MSG( component != NULL, false, + wxT( "No component associated with field" ) + text ); + + text = component->GetRef( (SCH_SHEET_PATH*) aAuxData ); + + // if( component->GetUnitCount() > 1 ) + // text << LIB_PART::SubReference( component->GetUnit() ); + + isReplaced = EDA_ITEM::Replace( aSearchData, text ); + + if( isReplaced ) + component->SetRef( (SCH_SHEET_PATH*) aAuxData, text ); + } + else + { + isReplaced = EDA_ITEM::Replace( aSearchData, m_Text ); + } + + return isReplaced; +} + + +void SCH_FIELD::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); +} + + +wxString SCH_FIELD::GetSelectMenuText() const +{ + wxString tmp; + tmp.Printf( _( "Field %s" ), GetChars( GetName() ) ); + + return tmp; +} + + +wxString SCH_FIELD::GetName( bool aUseDefaultName ) const +{ + if( !m_name.IsEmpty() ) + return m_name; + else if( aUseDefaultName ) + return TEMPLATE_FIELDNAME::GetDefaultFieldName( m_id ); + + return wxEmptyString; +} + + +BITMAP_DEF SCH_FIELD::GetMenuImage() const +{ + if( m_id == REFERENCE ) + return edit_comp_ref_xpm; + + if( m_id == VALUE ) + return edit_comp_value_xpm; + + if( m_id == FOOTPRINT ) + return edit_comp_footprint_xpm; + + return edit_text_xpm; +} + + +bool SCH_FIELD::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + // Do not hit test hidden or empty fields. + if( !IsVisible() || IsVoid() ) + return false; + + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool SCH_FIELD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + // Do not hit test hidden fields. + if( !IsVisible() || IsVoid() ) + return false; + + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +void SCH_FIELD::Plot( PLOTTER* aPlotter ) +{ + SCH_COMPONENT* parent = ( SCH_COMPONENT* ) GetParent(); + + wxCHECK_RET( parent != NULL && parent->Type() == SCH_COMPONENT_T, + wxT( "Cannot plot field with invalid parent." ) ); + + EDA_COLOR_T color = GetLayerColor( GetLayer() ); + + if( m_Attributs & TEXT_NO_VISIBLE ) + return; + + if( IsVoid() ) + return; + + /* Calculate the text orientation, according to the component + * orientation/mirror */ + int orient = m_Orient; + + if( parent->GetTransform().y1 ) // Rotate component 90 deg. + { + if( orient == TEXT_ORIENT_HORIZ ) + orient = TEXT_ORIENT_VERT; + else + orient = TEXT_ORIENT_HORIZ; + } + + /* Calculate the text justification, according to the component + * orientation/mirror + * this is a bit complicated due to cumulative calculations: + * - numerous cases (mirrored or not, rotation) + * - the DrawGraphicText function recalculate also H and H justifications + * according to the text orientation. + * - When a component is mirrored, the text is not mirrored and + * justifications are complicated to calculate + * so the more easily way is to use no justifications ( Centered text ) + * and use GetBoundaryBox to know the text coordinate considered as centered + */ + EDA_RECT BoundaryBox = GetBoundingBox(); + EDA_TEXT_HJUSTIFY_T hjustify = GR_TEXT_HJUSTIFY_CENTER; + EDA_TEXT_VJUSTIFY_T vjustify = GR_TEXT_VJUSTIFY_CENTER; + wxPoint textpos = BoundaryBox.Centre(); + + int thickness = GetPenSize(); + + aPlotter->Text( textpos, color, GetFullyQualifiedText(), orient, m_Size, hjustify, vjustify, + thickness, m_Italic, m_Bold ); +} + + +void SCH_FIELD::SetPosition( const wxPoint& aPosition ) +{ + SCH_COMPONENT* component = (SCH_COMPONENT*) GetParent(); + + wxPoint pos = ( (SCH_COMPONENT*) GetParent() )->GetPosition(); + + // Actual positions are calculated by the rotation/mirror transform of the + // parent component of the field. The inverse transfrom is used to calculate + // the position relative to the parent component. + wxPoint pt = aPosition - pos; + + m_Pos = pos + component->GetTransform().InverseTransform().TransformCoordinate( pt ); +} + + +wxPoint SCH_FIELD::GetPosition() const +{ + + SCH_COMPONENT* component = (SCH_COMPONENT*) GetParent(); + + wxPoint pos = m_Pos - component->GetPosition(); + + return component->GetTransform().TransformCoordinate( pos ) + component->GetPosition(); +} diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h new file mode 100644 index 00000000..8b458bc2 --- /dev/null +++ b/eeschema/sch_field.h @@ -0,0 +1,202 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_field.h + * @brief Definition of the SCH_FIELD class for Eeschema. + */ + +#ifndef CLASS_SCH_FIELD_H +#define CLASS_SCH_FIELD_H + + +#include +#include +#include + + +class SCH_EDIT_FRAME; +class SCH_COMPONENT; +class LIB_FIELD; + + +/** + * Class SCH_FIELD + * instances are attached to a component and provide a place for the component's value, + * reference designator, footprint, and user definable name-value pairs of arbitrary purpose. + * + *
      • Field 0 is reserved for the component reference.
      • + *
      • Field 1 is reserved for the component value.
      • + *
      • Field 2 is reserved for the component footprint.
      • + *
      • Field 3 is reserved for the component data sheet file.
      • + *
      • Field 4 and higher are user defineable.
      + */ + +class SCH_FIELD : public SCH_ITEM, public EDA_TEXT +{ + int m_id; ///< Field index, @see enum NumFieldType + + wxString m_name; + +public: + SCH_FIELD( const wxPoint& aPos, int aFieldId, SCH_COMPONENT* aParent, + wxString aName = wxEmptyString ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_FIELD(); + + wxString GetClass() const + { + return wxT( "SCH_FIELD" ); + } + + /** + * Function GetName + * returns the field name. + * + * @param aUseDefaultName When true return the default field name if the field name is + * empty. Otherwise the default field name is returned. + * @return A wxString object containing the name of the field. + */ + wxString GetName( bool aUseDefaultName = true ) const; + + void SetName( const wxString& aName ) { m_name = aName; } + + int GetId() const { return m_id; } + + void SetId( int aId ) { m_id = aId; } + + /** + * Function GetFullyQualifiedText + * returns the fully qualified field text by allowing for the part suffix to be added + * to the reference designator field if the component has multiple parts. For all other + * fields this is the equivalent of EDA_TEXT::GetText(). + * + * @return a const wxString object containing the field's string. + */ + const wxString GetFullyQualifiedText() const; + + void Place( SCH_EDIT_FRAME* frame, wxDC* DC ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + /** + * Function IsVoid + * returns true if the field is either empty or holds "~". + */ + bool IsVoid() const + { + size_t len = m_Text.Len(); + + return len == 0 || ( len == 1 && m_Text[0] == wxChar( '~' ) ); + } + + void SwapData( SCH_ITEM* aItem ); + + /** + * Function ImportValues + * copy parameters from a source. + * Pointers and specific values (position) are not copied + * @param aSource = the LIB_FIELD to read + */ + void ImportValues( const LIB_FIELD& aSource ); + + int GetPenSize() const; + + /** + * Function IsVisible + * @return true is this field is visible, false if flagged invisible + */ + bool IsVisible() const + { + return (m_Attributs & TEXT_NO_VISIBLE) == 0 ? true : false; + } + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + bool Save( FILE* aFile ) const; + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + m_Pos += aMoveVector; + } + + + void Rotate( wxPoint aPosition ); + + /** + * @copydoc SCH_ITEM::MirrorX() + * + * This overload does nothing. Fields are never mirrored alone. They are moved + * when the parent component is mirrored. This function is only needed by the + * pure function of the master class. + */ + void MirrorX( int aXaxis_position ) + { + } + + /** + * @copydoc SCH_ITEM::MirrorY() + * + * This overload does nothing. Fields are never mirrored alone. They are moved + * when the parent component is mirrored. This function is only needed by the + * pure function of the master class. + */ + void MirrorY( int aYaxis_position ) + { + } + + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + bool Replace( wxFindReplaceData& aSearchData, void* aAuxData = NULL ); + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const; + + bool IsReplaceable() const { return true; } + + wxPoint GetPosition() const; + + void SetPosition( const wxPoint& aPosition ); + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif +}; + + +#endif /* CLASS_SCH_FIELD_H */ diff --git a/eeschema/sch_item_struct.cpp b/eeschema/sch_item_struct.cpp new file mode 100644 index 00000000..047d5c86 --- /dev/null +++ b/eeschema/sch_item_struct.cpp @@ -0,0 +1,151 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_item_struct.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +const wxString traceFindItem( wxT( "KicadFindItem" ) ); + + +bool sort_schematic_items( const SCH_ITEM* aItem1, const SCH_ITEM* aItem2 ) +{ + return *aItem1 < *aItem2; +} + + +/* Constructor and destructor for SCH_ITEM */ +/* They are not inline because this creates problems with gcc at linking time + * in debug mode + */ + +SCH_ITEM::SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType ) : + EDA_ITEM( aParent, aType ) +{ + m_Layer = LAYER_WIRE; // It's only a default, in fact +} + + +SCH_ITEM::SCH_ITEM( const SCH_ITEM& aItem ) : + EDA_ITEM( aItem ) +{ + m_Layer = aItem.m_Layer; +} + + +SCH_ITEM::~SCH_ITEM() +{ + // Do not let the connections container go out of scope with any objects or they + // will be deleted by the container will cause the Eeschema to crash. These objects + // are owned by the sheet object container. + if( !m_connections.empty() ) + m_connections.clear(); +} + + +bool SCH_ITEM::IsConnected( const wxPoint& aPosition ) const +{ + if( m_Flags & STRUCT_DELETED || m_Flags & SKIP_STRUCT ) + return false; + + return doIsConnected( aPosition ); +} + + +void SCH_ITEM::SwapData( SCH_ITEM* aItem ) +{ + wxFAIL_MSG( wxT( "SwapData() method not implemented for class " ) + GetClass() ); +} + + +bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const +{ + wxCHECK_MSG( false, this->Type() < aItem.Type(), + wxT( "Less than operator not defined for " ) + GetClass() ); +} + + +void SCH_ITEM::Plot( PLOTTER* aPlotter ) +{ + wxFAIL_MSG( wxT( "Plot() method not implemented for class " ) + GetClass() ); +} + + +std::string SCH_ITEM::FormatInternalUnits( int aValue ) +{ + char buf[50]; + double engUnits = aValue; + int len; + + if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 ) + { + len = snprintf( buf, sizeof(buf), "%.10f", engUnits ); + + while( --len > 0 && buf[len] == '0' ) + buf[len] = '\0'; + + ++len; + } + else + { + len = snprintf( buf, sizeof(buf), "%.10g", engUnits ); + } + + return std::string( buf, len ); +} + + +std::string SCH_ITEM::FormatAngle( double aAngle ) +{ + char temp[50]; + int len; + + len = snprintf( temp, sizeof(temp), "%.10g", aAngle / 10.0 ); + + return std::string( temp, len ); +} + + +std::string SCH_ITEM::FormatInternalUnits( const wxPoint& aPoint ) +{ + return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y ); +} + + +std::string SCH_ITEM::FormatInternalUnits( const wxSize& aSize ) +{ + return FormatInternalUnits( aSize.GetWidth() ) + " " + FormatInternalUnits( aSize.GetHeight() ); +} diff --git a/eeschema/sch_item_struct.h b/eeschema/sch_item_struct.h new file mode 100644 index 00000000..c53f40ae --- /dev/null +++ b/eeschema/sch_item_struct.h @@ -0,0 +1,432 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_item_struct.h + * @brief Base schematic object class definition. + */ + +#ifndef SCH_ITEM_STRUCT_H +#define SCH_ITEM_STRUCT_H + +#include +#include +#include + +#include + +class SCH_ITEM; +class SCH_SHEET_PATH; +class LINE_READER; +class SCH_EDIT_FRAME; +class wxFindReplaceData; +class PLOTTER; +class NETLIST_OBJECT; +class NETLIST_OBJECT_LIST; + + +typedef boost::ptr_vector< SCH_ITEM > SCH_ITEMS; +typedef SCH_ITEMS::iterator SCH_ITEMS_ITR; +typedef std::vector< SCH_ITEMS_ITR > SCH_ITEMS_ITRS; + + +#define FMT_IU SCH_ITEM::FormatInternalUnits +#define FMT_ANGLE SCH_ITEM::FormatAngle + + +/// Flag to enable find item tracing using the WXTRACE environment variable. This +/// flag generates a lot of debug output. +extern const wxString traceFindItem; + + +enum DANGLING_END_T { + UNKNOWN = 0, + WIRE_START_END, + WIRE_END_END, + BUS_START_END, + BUS_END_END, + JUNCTION_END, + PIN_END, + LABEL_END, + ENTRY_END, + SHEET_LABEL_END, + NO_CONNECT_END, +}; + + +/** + * Class DANGLING_END_ITEM + * is a helper class used to store the state of schematic items that can be connected to + * other schematic items. + */ +class DANGLING_END_ITEM +{ +private: + /// A pointer to the connectable object. + const EDA_ITEM* m_item; + + /// The position of the connection point. + wxPoint m_pos; + + /// The type of connection of #m_item. + DANGLING_END_T m_type; + +public: + DANGLING_END_ITEM( DANGLING_END_T aType, const EDA_ITEM* aItem, const wxPoint& aPosition ) + { + m_item = aItem; + m_type = aType; + m_pos = aPosition; + } + + wxPoint GetPosition() const { return m_pos; } + const EDA_ITEM* GetItem() const { return m_item; } + DANGLING_END_T GetType() const { return m_type; } +}; + + +/** + * Class SCH_ITEM + * is a base class for any item which can be embedded within the SCHEMATIC + * container class, and therefore instances of derived classes should only be + * found in EESCHEMA or other programs that use class SCHEMATIC and its contents. + * The corresponding class in Pcbnew is BOARD_ITEM. + */ +class SCH_ITEM : public EDA_ITEM +{ +protected: + LAYERSCH_ID m_Layer; + EDA_ITEMS m_connections; ///< List of items connected to this item. + wxPoint m_storedPos; ///< a temporary variable used in some move commands + ///> to store a initial pos (of the item or mouse cursor) + +public: + SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType ); + + SCH_ITEM( const SCH_ITEM& aItem ); + + ~SCH_ITEM(); + + virtual wxString GetClass() const + { + return wxT( "SCH_ITEM" ); + } + + /** + * Function SwapData + * swap the internal data structures \a aItem with the schematic item. + * Obviously, aItem must have the same type than me + * @param aItem The item to swap the data structures with. + */ + virtual void SwapData( SCH_ITEM* aItem ); + + SCH_ITEM* Next() const { return static_cast( Pnext ); } + SCH_ITEM* Back() const { return static_cast( Pback ); } + + /** + * Virtual function IsMovableFromAnchorPoint + * @return true for items which are moved with the anchor point at mouse cursor + * and false for items moved with no reference to anchor + * Usually return true for small items (labels, junctions) and false for + * items which can be large (hierarchical sheets, compoments) + */ + virtual bool IsMovableFromAnchorPoint() { return true; } + + wxPoint& GetStoredPos() { return m_storedPos; } + void SetStoredPos( wxPoint aPos ) { m_storedPos = aPos; } + + + /** + * Function GetLayer + * returns the layer this item is on. + */ + LAYERSCH_ID GetLayer() const { return m_Layer; } + + /** + * Function SetLayer + * sets the layer this item is on. + * @param aLayer The layer number. + */ + void SetLayer( LAYERSCH_ID aLayer ) { m_Layer = aLayer; } + + /** + * Function GetPenSize virtual pure + * @return the size of the "pen" that be used to draw or plot this item + */ + virtual int GetPenSize() const { return 0; } + + /** + * Function Draw + * Draw a schematic item. Each schematic item should have its own method + * @param aPanel DrawPanel to use (can be null) mainly used for clipping purposes. + * @param aDC Device Context (can be null) + * @param aOffset drawing Offset (usually wxPoint(0,0), + * but can be different when moving an object) + * @param aDrawMode GR_OR, GR_XOR, ... + * @param aColor UNSPECIFIED_COLOR to use the normal body item color, + * or force this color if it is a valid color + */ + virtual void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ) = 0; + + /** + * Function Move + * moves the item by \a aMoveVector to a new position. + * @param aMoveVector = the displacement vector + */ + virtual void Move( const wxPoint& aMoveVector ) = 0; + + /** + * Function MirrorY + * mirrors item relative to the Y axis about \a aYaxis_position. + * @param aYaxis_position The Y axis position to mirror around. + */ + virtual void MirrorY( int aYaxis_position ) = 0; + + /** + * Function MirrorX + * mirrors item relative to the X axis about \a aXaxis_position. + * @param aXaxis_position The X axis position to mirror around. + */ + virtual void MirrorX( int aXaxis_position ) = 0; + + /** + * Function Rotate + * rotates the item around \a aPosition 90 degrees in the clockwise direction. + * @param aPosition A reference to a wxPoint object containing the coordinates to + * rotate around. + */ + virtual void Rotate( wxPoint aPosition ) = 0; + + /** + * Function Save + * writes the data structures for this object out to a FILE in "*.sch" format. + * @param aFile The FILE to write to. + * @return bool - true if success writing else false. + */ + virtual bool Save( FILE* aFile ) const = 0; + + /** + * Function Load + * reads a schematic item from \a aLine in a .sch file. + * + * @param aLine - Essentially this is file to read the object from. + * @param aErrorMsg - Description of the error if an error occurs while loading the object. + * @return True if the object loaded successfully. + */ + virtual bool Load( LINE_READER& aLine, wxString& aErrorMsg ) { return false; } + + /** + * Function GetEndPoints + * adds the schematic item end points to \a aItemList if the item has end points. + * + * The default version doesn't do anything since many of the schematic object cannot + * be tested for dangling ends. If you add a new schematic item that can have a + * dangling end ( no connect ), override this method to provide the correct end + * points. + * + * @param aItemList - List of DANGLING_END_ITEMS to add to. + */ + virtual void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) {} + + /** + * Function IsDanglingStateChanged + * tests the schematic item to \a aItemList to check if it's dangling state has changed. + * + * Note that the return value only true when the state of the test has changed. Use + * the IsDangling() method to get the current dangling state of the item. Some of + * the schematic objects cannot be tested for a dangling state, the default method + * always returns false. Only override the method if the item can be tested for a + * dangling state. + * + * @param aItemList - List of items to test item against. + * @return True if the dangling state has changed from it's current setting. + */ + virtual bool IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ) { return false; } + + virtual bool IsDangling() const { return false; } + + /** + * Function IsSelectStateChanged + * checks if the selection state of an item inside \a aRect has changed. + * + * This is used by the block selection code to verify if an item is selected or not. + * True is be return anytime the select state changes. If you need to know the + * the current selection state, use the IsSelected() method. + * + * @param aRect - Rectangle to test against. + */ + virtual bool IsSelectStateChanged( const wxRect& aRect ) { return false; } + + /** + * Function IsConnectable + * returns true if the schematic item can connect to another schematic item. + */ + virtual bool IsConnectable() const { return false; } + + /** + * Function GetConnectionPoints + * add all the connection points for this item to \a aPoints. + * + * Not all schematic items have connection points so the default method does nothing. + * + * @param aPoints List of connection points to add to. + */ + virtual void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const { } + + /** + * Function ClearConnections + * clears all of the connection items from the list. + * + * The vector release method is used to prevent the item pointers from being deleted. + * Do not use the vector erase method on the connection list. + */ + void ClearConnections() { m_connections.clear(); } + + /** + * Function IsConnected + * tests the item to see if it is connected to \a aPoint. + * + * @param aPoint A reference to a wxPoint object containing the coordinates to test. + * @return True if connection to \a aPoint exists. + */ + bool IsConnected( const wxPoint& aPoint ) const; + + /** @copydoc EDA_ITEM::HitTest(const wxPoint&) */ + virtual bool HitTest( const wxPoint& aPosition ) const + { + return HitTest( aPosition, 0 ); + } + + /** + * Function HitTest + * tests if \a aPosition is contained within or on the bounding box of an item. + * + * @param aPosition A reference to a wxPoint object containing the coordinates to test. + * @param aAccuracy Increase the item bounding box by this amount. + * @return True if \a aPosition is within the item bounding box. + */ + virtual bool HitTest( const wxPoint& aPosition, int aAccuracy ) const { return false; } + + /** + * Function HitTest + * tests if \a aRect intersects or is contained within the bounding box of an item. + * + * @param aRect A reference to a EDA_RECT object containing the rectangle to test. + * @param aContained Set to true to test for containment instead of an intersection. + * @param aAccuracy Increase \a aRect by this amount. + * @return True if \a aRect contains or intersects the item bounding box. + */ + virtual bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const + { + return false; + } + + virtual bool CanIncrementLabel() const { return false; } + + /** + * Function Plot + * plots the schematic item to \a aPlotter. + * + * @param aPlotter A pointer to a #PLOTTER object. + */ + virtual void Plot( PLOTTER* aPlotter ); + + /** + * Function GetNetListItem + * creates a new #NETLIST_OBJECT for the schematic object and adds it to + * \a aNetListItems. + *

      + * Not all schematic objects have net list items associated with them. This + * method only needs to be overridden for those schematic objects that have + * net list objects associated with them. + *

      + */ + virtual void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) { } + + /** + * Function GetPosition + * @return A wxPoint object containing the schematic item position. + */ + virtual wxPoint GetPosition() const = 0; + + /** + * Function SetPosition + * set the schematic item position to \a aPosition. + * + * @param aPosition A reference to a wxPoint object containing the new position. + */ + virtual void SetPosition( const wxPoint& aPosition ) = 0; + + virtual bool operator <( const SCH_ITEM& aItem ) const; + + /** + * Function FormatInternalUnits + * converts \a aValue from schematic internal units to a string appropriate for writing + * to file. + * + * @param aValue A coordinate value to convert. + * @return A std::string object containing the converted value. + */ + static std::string FormatInternalUnits( int aValue ); + + /** + * Function FormatAngle + * converts \a aAngle from board units to a string appropriate for writing to file. + * + * @note Internal angles for board items can be either degrees or tenths of degree + * on how KiCad is built. + * @param aAngle A angle value to convert. + * @return A std::string object containing the converted angle. + */ + static std::string FormatAngle( double aAngle ); + + static std::string FormatInternalUnits( const wxPoint& aPoint ); + + static std::string FormatInternalUnits( const wxSize& aSize ); + +private: + /** + * Function doIsConnected + * provides the object specific test to see if it is connected to \a aPosition. + * + * @note Override this function if the derived object can be connect to another + * object such as a wire, bus, or junction. Do not override this function + * for objects that cannot have connections. The default will always return + * false. This functions is call through the public function IsConnected() + * which performs tests common to all schematic items before calling the + * item specific connection testing. + * + * @param aPosition A reference to a wxPoint object containing the test position. + * @return True if connection to \a aPosition exists. + */ + virtual bool doIsConnected( const wxPoint& aPosition ) const { return false; } +}; + + +extern bool sort_schematic_items( const SCH_ITEM* aItem1, const SCH_ITEM* aItem2 ); + + +#endif /* SCH_ITEM_STRUCT_H */ diff --git a/eeschema/sch_junction.cpp b/eeschema/sch_junction.cpp new file mode 100644 index 00000000..9c08b639 --- /dev/null +++ b/eeschema/sch_junction.cpp @@ -0,0 +1,235 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_junction.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +int SCH_JUNCTION::m_symbolSize = 40; // Default diameter of the junction symbol + +SCH_JUNCTION::SCH_JUNCTION( const wxPoint& pos ) : + SCH_ITEM( NULL, SCH_JUNCTION_T ) +{ + m_pos = pos; + m_Layer = LAYER_JUNCTION; +} + + +bool SCH_JUNCTION::Save( FILE* aFile ) const +{ + bool success = true; + + if( fprintf( aFile, "Connection ~ %-4d %-4d\n", m_pos.x, m_pos.y ) == EOF ) + { + success = false; + } + + return success; +} + + +EDA_ITEM* SCH_JUNCTION::Clone() const +{ + return new SCH_JUNCTION( *this ); +} + + +void SCH_JUNCTION::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_JUNCTION_T), + wxT( "Cannot swap junction data with invalid item." ) ); + + SCH_JUNCTION* item = (SCH_JUNCTION*) aItem; + std::swap( m_pos, item->m_pos ); +} + + +bool SCH_JUNCTION::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char name[256]; + char* line = (char*) aLine; + + while( (*line != ' ' ) && *line ) + line++; + + if( sscanf( line, "%255s %d %d", name, &m_pos.x, &m_pos.y ) != 3 ) + { + aErrorMsg.Printf( wxT( "Eeschema file connection load error at line %d, aborted" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + return true; +} + + +const EDA_RECT SCH_JUNCTION::GetBoundingBox() const +{ + EDA_RECT rect; + + rect.SetOrigin( m_pos ); + rect.Inflate( ( GetPenSize() + GetSymbolSize() ) / 2 ); + + return rect; +} + + +void SCH_JUNCTION::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + EDA_COLOR_T color; + + if( aColor >= 0 ) + color = aColor; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( aDC, aDrawMode ); + + GRFilledCircle( aPanel->GetClipBox(), aDC, m_pos.x + aOffset.x, m_pos.y + aOffset.y, + ( GetSymbolSize() / 2 ), 0, color, color ); +} + + +void SCH_JUNCTION::MirrorX( int aXaxis_position ) +{ + MIRROR( m_pos.y, aXaxis_position ); +} + + +void SCH_JUNCTION::MirrorY( int aYaxis_position ) +{ + MIRROR( m_pos.x, aYaxis_position ); +} + + +void SCH_JUNCTION::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_pos, aPosition, 900 ); +} + + +void SCH_JUNCTION::GetEndPoints( std::vector & aItemList ) +{ + DANGLING_END_ITEM item( JUNCTION_END, this, m_pos ); + aItemList.push_back( item ); +} + + +bool SCH_JUNCTION::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_pos ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_JUNCTION::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + aPoints.push_back( m_pos ); +} + + +void SCH_JUNCTION::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + + item->m_SheetPath = *aSheetPath; + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = (SCH_ITEM*) this; + item->m_Type = NET_JUNCTION; + item->m_Start = item->m_End = m_pos; + + aNetListItems.push_back( item ); +} + + +#if defined(DEBUG) +void SCH_JUNCTION::Show( int nestLevel, std::ostream& os ) const +{ + // XML output: + wxString s = GetClass(); + + NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << m_pos << "/>\n"; +} +#endif + + +bool SCH_JUNCTION::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool SCH_JUNCTION::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + if( m_Flags & STRUCT_DELETED || m_Flags & SKIP_STRUCT ) + return false; + + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +bool SCH_JUNCTION::doIsConnected( const wxPoint& aPosition ) const +{ + return m_pos == aPosition; +} + + +void SCH_JUNCTION::Plot( PLOTTER* aPlotter ) +{ + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + aPlotter->Circle( m_pos, GetSymbolSize(), FILLED_SHAPE ); +} diff --git a/eeschema/sch_junction.h b/eeschema/sch_junction.h new file mode 100644 index 00000000..0e93d846 --- /dev/null +++ b/eeschema/sch_junction.h @@ -0,0 +1,113 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_junction.h + */ + +#ifndef _SCH_JUNCTION_H_ +#define _SCH_JUNCTION_H_ + + +#include +class NETLIST_OBJECT_LIST; + +class SCH_JUNCTION : public SCH_ITEM +{ + wxPoint m_pos; // Position of the junction. + static int m_symbolSize; // diameter of the junction graphic symbol + +public: + SCH_JUNCTION( const wxPoint& pos = wxPoint( 0, 0 ) ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_JUNCTION() { } + + wxString GetClass() const + { + return wxT( "SCH_JUNCTION" ); + } + + static int GetSymbolSize() { return m_symbolSize; } + static void SetSymbolSize( int aSize ) { m_symbolSize = aSize; } + + void SwapData( SCH_ITEM* aItem ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + void Move( const wxPoint& aMoveVector ) + { + m_pos += aMoveVector; + } + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + void GetEndPoints( std::vector & aItemList ); + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const { return true; } + + void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const; + + wxString GetSelectMenuText() const { return wxString( _( "Junction" ) ); } + + BITMAP_DEF GetMenuImage() const { return add_junction_xpm; } + + void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, SCH_SHEET_PATH* aSheetPath ); + + wxPoint GetPosition() const { return m_pos; } + + void SetPosition( const wxPoint& aPosition ) { m_pos = aPosition; } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, + int aAccuracy = 0 ) const; + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif + +private: + bool doIsConnected( const wxPoint& aPosition ) const; +}; + + +#endif // _SCH_JUNCTION_H_ diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp new file mode 100644 index 00000000..72efb5cb --- /dev/null +++ b/eeschema/sch_line.cpp @@ -0,0 +1,611 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_line.cpp + * @brief Class SCH_LINE implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +SCH_LINE::SCH_LINE( const wxPoint& pos, int layer ) : + SCH_ITEM( NULL, SCH_LINE_T ) +{ + m_start = pos; + m_end = pos; + m_startIsDangling = m_endIsDangling = false; + + switch( layer ) + { + default: + m_Layer = LAYER_NOTES; + break; + + case LAYER_WIRE: + m_Layer = LAYER_WIRE; + break; + + case LAYER_BUS: + m_Layer = LAYER_BUS; + break; + } +} + + +SCH_LINE::SCH_LINE( const SCH_LINE& aLine ) : + SCH_ITEM( aLine ) +{ + m_start = aLine.m_start; + m_end = aLine.m_end; + m_startIsDangling = m_endIsDangling = false; +} + + +EDA_ITEM* SCH_LINE::Clone() const +{ + return new SCH_LINE( *this ); +} + + +void SCH_LINE::Move( const wxPoint& aOffset ) +{ + if( (m_Flags & STARTPOINT) == 0 && aOffset != wxPoint( 0, 0 ) ) + { + m_start += aOffset; + SetModified(); + } + + if( (m_Flags & ENDPOINT) == 0 && aOffset != wxPoint( 0, 0 ) ) + { + m_end += aOffset; + SetModified(); + } +} + + +#if defined(DEBUG) + +void SCH_LINE::Show( int nestLevel, std::ostream& os ) const +{ + NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() + << " layer=\"" << m_Layer << '"' + << " startIsDangling=\"" << m_startIsDangling + << '"' << " endIsDangling=\"" + << m_endIsDangling << '"' << ">" + << " " + << " " << "\n"; +} + +#endif + + +const EDA_RECT SCH_LINE::GetBoundingBox() const +{ + int width = 25; + + int xmin = std::min( m_start.x, m_end.x ) - width; + int ymin = std::min( m_start.y, m_end.y ) - width; + + int xmax = std::max( m_start.x, m_end.x ) + width; + int ymax = std::max( m_start.y, m_end.y ) + width; + + // return a rectangle which is [pos,dim) in nature. therefore the +1 + EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) ); + + return ret; +} + + +double SCH_LINE::GetLength() const +{ + return GetLineLength( m_start, m_end ); +} + + +bool SCH_LINE::Save( FILE* aFile ) const +{ + bool success = true; + + const char* layer = "Notes"; + const char* width = "Line"; + + if( GetLayer() == LAYER_WIRE ) + layer = "Wire"; + + if( GetLayer() == LAYER_BUS ) + layer = "Bus"; + + if( fprintf( aFile, "Wire %s %s\n", layer, width ) == EOF ) + { + success = false; + } + + if( fprintf( aFile, "\t%-4d %-4d %-4d %-4d\n", m_start.x, m_start.y, + m_end.x, m_end.y ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_LINE::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char Name1[256]; + char Name2[256]; + char* line = (char*) aLine; + + while( (*line != ' ' ) && *line ) + line++; + + if( sscanf( line, "%255s %255s", Name1, Name2 ) != 2 ) + { + aErrorMsg.Printf( wxT( "Eeschema file segment error at line %d, aborted" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + m_Layer = LAYER_NOTES; + + if( Name1[0] == 'W' ) + m_Layer = LAYER_WIRE; + + if( Name1[0] == 'B' ) + m_Layer = LAYER_BUS; + + if( !aLine.ReadLine() || sscanf( (char*) aLine, "%d %d %d %d ", + &m_start.x, &m_start.y, &m_end.x, &m_end.y ) != 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file Segment struct error at line %d, aborted" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( (char*) aLine ); + return false; + } + + return true; +} + + +int SCH_LINE::GetPenSize() const +{ + + if( m_Layer == LAYER_BUS ) + return GetDefaultBusThickness(); + + return GetDefaultLineThickness(); +} + + +void SCH_LINE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE DrawMode, EDA_COLOR_T Color ) +{ + EDA_COLOR_T color; + int width = GetPenSize(); + + if( Color >= 0 ) + color = Color; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( DC, DrawMode ); + + wxPoint start = m_start; + wxPoint end = m_end; + + if( ( m_Flags & STARTPOINT ) == 0 ) + start += offset; + + if( ( m_Flags & ENDPOINT ) == 0 ) + end += offset; + + if( m_Layer == LAYER_NOTES ) + GRDashedLine( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y, width, color ); + else + GRLine( panel->GetClipBox(), DC, start, end, width, color ); + + if( m_startIsDangling ) + DrawDanglingSymbol( panel, DC, start, color ); + + if( m_endIsDangling ) + DrawDanglingSymbol( panel, DC, end, color ); +} + + +void SCH_LINE::MirrorX( int aXaxis_position ) +{ + MIRROR( m_start.y, aXaxis_position ); + MIRROR( m_end.y, aXaxis_position ); +} + + +void SCH_LINE::MirrorY( int aYaxis_position ) +{ + MIRROR( m_start.x, aYaxis_position ); + MIRROR( m_end.x, aYaxis_position ); +} + + +void SCH_LINE::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_start, aPosition, 900 ); + RotatePoint( &m_end, aPosition, 900 ); +} + + +/* + * helper sort function, used by MergeOverlap + * sorts ref and test by x values, or (for same x values) by y values + */ +bool sort_by_ends_position(const wxPoint * ref, const wxPoint * tst ) +{ + if( ref->x == tst->x ) + return ref->y < tst->y; + return ref->x < tst->x; +} + +/* + * MergeOverlap try to merge 2 lines that are colinear. + * this function expects these 2 lines have at least a common end + */ +bool SCH_LINE::MergeOverlap( SCH_LINE* aLine ) +{ + wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false, + wxT( "Cannot test line segment for overlap." ) ); + + if( this == aLine || GetLayer() != aLine->GetLayer() ) + return false; + + // Search for a common end: + if( m_start == aLine->m_start ) + { + if( m_end == aLine->m_end ) // Trivial case + return true; + } + else if( m_start == aLine->m_end ) + { + if( m_end == aLine->m_start ) // Trivial case + return true; + } + else if( m_end == aLine->m_end ) + { + std::swap( aLine->m_start, aLine->m_end ); + } + else if( m_end != aLine->m_start ) + { + // No common end point, segments cannot be merged. + return false; + } + + bool colinear = false; + + /* Test alignment: */ + if( m_start.y == m_end.y ) // Horizontal segment + { + if( aLine->m_start.y == aLine->m_end.y ) + { + colinear = true; + } + } + else if( m_start.x == m_end.x ) // Vertical segment + { + if( aLine->m_start.x == aLine->m_end.x ) + { + colinear = true; + } + } + else + { + if( atan2( (double) ( m_start.x - m_end.x ), (double) ( m_start.y - m_end.y ) ) + == atan2( (double) ( aLine->m_start.x - aLine->m_end.x ), + (double) ( aLine->m_start.y - aLine->m_end.y ) ) ) + { + colinear = true; + } + } + + // Make a segment which merge the 2 segments + // we must find the extremums + // i.e. the more to the left and to the right points, or + // for horizontal segments the uppermost and the lowest point + if( colinear ) + { + static std::vector candidates; + candidates.clear(); + candidates.push_back( &m_start ); + candidates.push_back( &m_end ); + candidates.push_back( &aLine->m_start ); + candidates.push_back( &aLine->m_end ); + sort( candidates.begin(), candidates.end(), sort_by_ends_position ); + wxPoint tmp = *candidates[3]; + m_start = *candidates[0]; + m_end = tmp; + return true; + } + return false; +} + + +void SCH_LINE::GetEndPoints( std::vector & aItemList ) +{ + if( GetLayer() == LAYER_NOTES ) + return; + + if( ( GetLayer() == LAYER_BUS ) || ( GetLayer() == LAYER_WIRE ) ) + { + DANGLING_END_ITEM item( (GetLayer() == LAYER_BUS) ? BUS_START_END : WIRE_START_END, this, + m_start ); + aItemList.push_back( item ); + + DANGLING_END_ITEM item1( (GetLayer() == LAYER_BUS) ? BUS_END_END : WIRE_END_END, this, + m_end ); + aItemList.push_back( item1 ); + } +} + + +bool SCH_LINE::IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ) +{ + bool previousStartState = m_startIsDangling; + bool previousEndState = m_endIsDangling; + + m_startIsDangling = m_endIsDangling = true; + + if( GetLayer() == LAYER_WIRE ) + { + BOOST_FOREACH( DANGLING_END_ITEM item, aItemList ) + { + if( item.GetItem() == this ) + continue; + + if( item.GetType() == NO_CONNECT_END ) + continue; + + if( m_start == item.GetPosition() ) + m_startIsDangling = false; + + if( m_end == item.GetPosition() ) + m_endIsDangling = false; + + if( (m_startIsDangling == false) && (m_endIsDangling == false) ) + break; + } + } + else if( GetLayer() == LAYER_BUS || GetLayer() == LAYER_NOTES ) + { + // Lines on the notes layer and the bus layer cannot be tested for dangling ends. + previousStartState = previousEndState = m_startIsDangling = m_endIsDangling = false; + } + + return ( previousStartState != m_startIsDangling ) || ( previousEndState != m_endIsDangling ); +} + + +bool SCH_LINE::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_start ) && aRect.Contains( m_end ) ) + { + SetFlags( SELECTED ); + ClearFlags( STARTPOINT | ENDPOINT ); + } + else if( aRect.Contains( m_start ) ) + { + ClearFlags( STARTPOINT ); + SetFlags( SELECTED | ENDPOINT ); + } + else if( aRect.Contains( m_end ) ) + { + ClearFlags( ENDPOINT ); + SetFlags( SELECTED | STARTPOINT ); + } + else + { + ClearFlags( SELECTED | STARTPOINT | ENDPOINT ); + } + + return previousState != IsSelected(); +} + + +bool SCH_LINE::IsConnectable() const +{ + if( m_Layer == LAYER_WIRE || m_Layer == LAYER_BUS ) + return true; + + return false; +} + + +void SCH_LINE::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + aPoints.push_back( m_start ); + aPoints.push_back( m_end ); +} + + +wxString SCH_LINE::GetSelectMenuText() const +{ + wxString menuText, txtfmt, orient; + + if( m_start.x == m_end.x ) + orient = _("Vert."); + else if( m_start.y == m_end.y ) + orient = _("Horiz."); + + switch( m_Layer ) + { + case LAYER_NOTES: + txtfmt = _( "%s Graphic Line from (%s,%s) to (%s,%s) " ); + break; + + case LAYER_WIRE: + txtfmt = _( "%s Wire from (%s,%s) to (%s,%s)" ); + break; + + case LAYER_BUS: + txtfmt = _( "%s Bus from (%s,%s) to (%s,%s)" ); + break; + + default: + txtfmt += _( "%s Line on Unknown Layer from (%s,%s) to (%s,%s)" ); + } + + menuText.Printf( txtfmt, GetChars( orient ), + GetChars( CoordinateToString( m_start.x ) ), + GetChars( CoordinateToString( m_start.y ) ), + GetChars( CoordinateToString( m_end.x ) ), + GetChars( CoordinateToString( m_end.y ) ) ); + + return menuText; +} + + +BITMAP_DEF SCH_LINE::GetMenuImage() const +{ + if( m_Layer == LAYER_NOTES ) + return add_dashed_line_xpm; + else if( m_Layer == LAYER_WIRE ) + return add_line_xpm; + + return add_bus_xpm; +} + + +void SCH_LINE::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + // Net list item not required for graphic lines. + if( (GetLayer() != LAYER_BUS) && (GetLayer() != LAYER_WIRE) ) + return; + + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + item->m_SheetPath = *aSheetPath; + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = (SCH_ITEM*) this; + item->m_Start = m_start; + item->m_End = m_end; + + if( GetLayer() == LAYER_BUS ) + { + item->m_Type = NET_BUS; + } + else /* WIRE */ + { + item->m_Type = NET_SEGMENT; + } + + aNetListItems.push_back( item ); +} + + +bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const +{ + if( Type() != aItem.Type() ) + return Type() < aItem.Type(); + + SCH_LINE* line = (SCH_LINE*) &aItem; + + if( GetLength() != line->GetLength() ) + return GetLength() < line->GetLength(); + + if( m_start.x != line->m_start.x ) + return m_start.x < line->m_start.x; + + if( m_start.y != line->m_start.y ) + return m_start.y < line->m_start.y; + + return false; +} + + +bool SCH_LINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + return TestSegmentHit( aPosition, m_start, m_end, aAccuracy ); +} + + +bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) + return false; + + EDA_RECT rect = aRect; + + if ( aAccuracy ) + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( m_start ) && rect.Contains( m_end ); + + return rect.Intersects( m_start, m_end ); +} + + +bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const +{ + if( m_Layer != LAYER_WIRE && m_Layer != LAYER_BUS ) + return false; + + return IsEndPoint( aPosition ); +} + + +void SCH_LINE::Plot( PLOTTER* aPlotter ) +{ + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + aPlotter->SetCurrentLineWidth( GetPenSize() ); + + if( m_Layer == LAYER_NOTES ) + aPlotter->SetDash( true ); + + aPlotter->MoveTo( m_start ); + aPlotter->FinishTo( m_end ); + + if( m_Layer == LAYER_NOTES ) + aPlotter->SetDash( false ); +} + + +void SCH_LINE::SetPosition( const wxPoint& aPosition ) +{ + m_end = m_end - ( m_start - aPosition ); + m_start = aPosition; +} diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h new file mode 100644 index 00000000..87a3972a --- /dev/null +++ b/eeschema/sch_line.h @@ -0,0 +1,157 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_line.h + */ + +#ifndef _SCH_LINE_H_ +#define _SCH_LINE_H_ + + +#include + +class NETLIST_OBJECT_LIST; + +/** + * Class SCH_LINE + * is a segment description base class to describe items which have 2 end + * points (track, wire, draw line ...) + */ +class SCH_LINE : public SCH_ITEM +{ + bool m_startIsDangling; ///< True if start point is not connected. + bool m_endIsDangling; ///< True if end point is not connected. + wxPoint m_start; ///< Line start point + wxPoint m_end; ///< Line end point + +public: + SCH_LINE( const wxPoint& pos = wxPoint( 0, 0 ), int layer = LAYER_NOTES ); + + SCH_LINE( const SCH_LINE& aLine ); + + ~SCH_LINE() { } + + SCH_LINE* Next() const { return (SCH_LINE*) Pnext; } + SCH_LINE* Back() const { return (SCH_LINE*) Pback; } + + wxString GetClass() const + { + return wxT( "SCH_LINE" ); + } + + bool IsEndPoint( const wxPoint& aPoint ) const + { + return aPoint == m_start || aPoint == m_end; + } + + bool IsNull() const { return m_start == m_end; } + + wxPoint GetStartPoint() const { return m_start; } + + void SetStartPoint( const wxPoint& aPosition ) { m_start = aPosition; } + + wxPoint GetEndPoint() const { return m_end; } + + void SetEndPoint( const wxPoint& aPosition ) { m_end = aPosition; } + + const EDA_RECT GetBoundingBox() const; // Virtual + + /** + * Function GetLength + * @return The length of the line segment. + */ + double GetLength() const; + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + int GetPenSize() const; + + void Move( const wxPoint& aMoveVector ); + + void MirrorX( int aXaxis_position ); + + void MirrorY( int aYaxis_position ); + + void Rotate( wxPoint aPosition ); + + /** + * Check line against \a aLine to see if it overlaps and merge if it does. + * + * This method will change the line to be equivalent of the line and \a aLine if the + * two lines overlap. This method is used to merge multiple line segments into a single + * line. + * + * @param aLine - Line to compare. + * @return True if lines overlap and the line was merged with \a aLine. + */ + bool MergeOverlap( SCH_LINE* aLine ); + + void GetEndPoints( std::vector& aItemList ); + + bool IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ); + + bool IsDangling() const { return m_startIsDangling || m_endIsDangling; } + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const; + + void GetConnectionPoints(std::vector< wxPoint >& aPoints ) const; + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const; + + void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, SCH_SHEET_PATH* aSheetPath ); + + bool operator <( const SCH_ITEM& aItem ) const; + + wxPoint GetPosition() const { return m_start; } + + void SetPosition( const wxPoint& aPosition ); + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif + +private: + bool doIsConnected( const wxPoint& aPosition ) const; +}; + + +#endif // _SCH_LINE_H_ diff --git a/eeschema/sch_marker.cpp b/eeschema/sch_marker.cpp new file mode 100644 index 00000000..334d277d --- /dev/null +++ b/eeschema/sch_marker.cpp @@ -0,0 +1,186 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_marker.cpp + * @brief Class SCH_MARKER implementation + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + + +/********************/ +/* class SCH_MARKER */ +/********************/ + +SCH_MARKER::SCH_MARKER() : SCH_ITEM( NULL, SCH_MARKER_T ), MARKER_BASE() +{ +} + + +SCH_MARKER::SCH_MARKER( const wxPoint& pos, const wxString& text ) : + SCH_ITEM( NULL, SCH_MARKER_T ), + MARKER_BASE( 0, pos, text, pos ) +{ +} + + +EDA_ITEM* SCH_MARKER::Clone() const +{ + return new SCH_MARKER( *this ); +} + + +#if defined(DEBUG) + +void SCH_MARKER::Show( int nestLevel, std::ostream& os ) const +{ + // for now, make it look like XML: + NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() + << GetPos() << "/>\n"; +} + +#endif + +/** + * Function Save (do nothing : markers are no more saved in files ) + * writes the data structures for this object out to a FILE in "*.brd" format. + * @param aFile The FILE to write to. + * @return bool - true if success writing else false. + */ +bool SCH_MARKER::Save( FILE* aFile ) const +{ + return true; +} + + +void SCH_MARKER::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + EDA_COLOR_T color = m_Color; + EDA_COLOR_T tmp = color; + + if( GetMarkerType() == MARKER_BASE::MARKER_ERC ) + { + color = ( GetErrorLevel() == MARKER_BASE::MARKER_SEVERITY_ERROR ) ? + GetLayerColor( LAYER_ERC_ERR ) : GetLayerColor( LAYER_ERC_WARN ); + } + + if( aColor < 0 ) + m_Color = color; + else + m_Color = aColor; + + DrawMarker( aPanel, aDC, aDrawMode, aOffset ); + m_Color = tmp; +} + + +bool SCH_MARKER::Matches( wxFindReplaceData& aSearchData, void* aAuxData, + wxPoint * aFindLocation ) +{ + if( SCH_ITEM::Matches( m_drc.GetErrorText(), aSearchData ) || + SCH_ITEM::Matches( m_drc.GetMainText(), aSearchData ) || + SCH_ITEM::Matches( m_drc.GetAuxiliaryText(), aSearchData ) ) + { + if( aFindLocation ) + *aFindLocation = m_Pos; + + return true; + } + + return false; +} + + +/** + * Function GetBoundingBox + * returns the orthogonal, bounding box of this object for display purposes. + * This box should be an enclosing perimeter for visible components of this + * object, and the units should be in the pcb or schematic coordinate system. + * It is OK to overestimate the size by a few counts. + */ +const EDA_RECT SCH_MARKER::GetBoundingBox() const +{ + return GetBoundingBoxMarker(); +} + + +void SCH_MARKER::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + aList.push_back( MSG_PANEL_ITEM( _( "Electronics Rule Check Error" ), + GetReporter().GetErrorText(), DARKRED ) ); +} + + +void SCH_MARKER::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); +} + + +void SCH_MARKER::MirrorX( int aXaxis_position ) +{ + m_Pos.y -= aXaxis_position; + m_Pos.y = -m_Pos.y; + m_Pos.y += aXaxis_position; +} + + +void SCH_MARKER::MirrorY( int aYaxis_position ) +{ + m_Pos.x -= aYaxis_position; + m_Pos.x = -m_Pos.x; + m_Pos.x += aYaxis_position; +} + + +bool SCH_MARKER::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_Pos ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +bool SCH_MARKER::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + return HitTestMarker( aPosition ); +} + diff --git a/eeschema/sch_marker.h b/eeschema/sch_marker.h new file mode 100644 index 00000000..0c534d9c --- /dev/null +++ b/eeschema/sch_marker.h @@ -0,0 +1,117 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/* + * @file sch_marker.h + * @brief SCH_MARKER class definition. + */ + +#ifndef TYPE_SCH_MARKER_H_ +#define TYPE_SCH_MARKER_H_ + +#include +#include + + +/* Names for corresponding types of markers: */ +extern const wxChar* NameMarqueurType[]; + + +class SCH_MARKER : public SCH_ITEM, public MARKER_BASE +{ +public: + SCH_MARKER(); + + SCH_MARKER( const wxPoint& aPos, const wxString& aText ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + wxString GetClass() const + { + return wxT( "SCH_MARKER" ); + } + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDraw_mode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + void Plot( PLOTTER* aPlotter ) + { + // SCH_MARKERs should not be plotted. However, SCH_ITEM will fail an + // assertion if we do not confirm this by locally implementing a no-op + // Plot(). + (void) aPlotter; + } + + bool Save( FILE* aFile ) const; + + EDA_RECT const GetBoundingBox() const; // Virtual + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + m_Pos += aMoveVector; + } + + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + /** + * Function Matches, virtual from the base class EDA_ITEM + * Compare DRC marker main and auxiliary text against search string. + * + * @param aSearchData - Criteria to search against. + * @param aAuxData A pointer to optional data required for the search or NULL + * if not used. + * @param aFindLocation - a wxPoint where to put the location of matched item. can be NULL. + * @return True if the DRC main or auxiliary text matches the search criteria. + */ + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + bool IsSelectStateChanged( const wxRect& aRect ); + + wxString GetSelectMenuText() const { return wxString( _( "ERC Marker" ) ); } + + BITMAP_DEF GetMenuImage() const { return erc_xpm; } + + wxPoint GetPosition() const { return m_Pos; } + + void SetPosition( const wxPoint& aPosition ) { m_Pos = aPosition; } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif +}; + +#endif // TYPE_SCH_MARKER_H_ diff --git a/eeschema/sch_no_connect.cpp b/eeschema/sch_no_connect.cpp new file mode 100644 index 00000000..dd1e9781 --- /dev/null +++ b/eeschema/sch_no_connect.cpp @@ -0,0 +1,252 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_no_connect.cpp + * @brief Class SCH_NO_CONNECT implementation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +SCH_NO_CONNECT::SCH_NO_CONNECT( const wxPoint& pos ) : + SCH_ITEM( NULL, SCH_NO_CONNECT_T ) +{ +#define DRAWNOCONNECT_SIZE 48 /* No symbol connection range. */ + m_pos = pos; + m_size.x = m_size.y = DRAWNOCONNECT_SIZE; +#undef DRAWNOCONNECT_SIZE + + SetLayer( LAYER_NOCONNECT ); +} + + +EDA_ITEM* SCH_NO_CONNECT::Clone() const +{ + return new SCH_NO_CONNECT( *this ); +} + + +void SCH_NO_CONNECT::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_NO_CONNECT_T), + wxT( "Cannot swap no connect data with invalid item." ) ); + + SCH_NO_CONNECT* item = (SCH_NO_CONNECT*)aItem; + std::swap( m_pos, item->m_pos ); + std::swap( m_size, item->m_size ); +} + + +const EDA_RECT SCH_NO_CONNECT::GetBoundingBox() const +{ + int delta = ( GetPenSize() + m_size.x ) / 2; + EDA_RECT box; + + box.SetOrigin( m_pos ); + box.Inflate( delta ); + + return box; +} + + +bool SCH_NO_CONNECT::Save( FILE* aFile ) const +{ + bool success = true; + + if( fprintf( aFile, "NoConn ~ %-4d %-4d\n", m_pos.x, m_pos.y ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_NO_CONNECT::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char name[256]; + char* line = (char*) aLine; + + while( (*line != ' ' ) && *line ) + line++; + + if( sscanf( line, "%255s %d %d", name, &m_pos.x, &m_pos.y ) != 3 ) + { + aErrorMsg.Printf( wxT( "Eeschema file No Connect load error at line %d" ), + aLine.LineNumber() ); + aErrorMsg << wxT( "\n" ) << FROM_UTF8( ((char*)aLine) ); + return false; + } + + return true; +} + + +void SCH_NO_CONNECT::GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) +{ + DANGLING_END_ITEM item( NO_CONNECT_END, this, m_pos ); + aItemList.push_back( item ); +} + + +int SCH_NO_CONNECT::GetPenSize() const +{ + return GetDefaultLineThickness(); +} + + +void SCH_NO_CONNECT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + int pX, pY; + int delta = m_size.x / 2; + int width = GetDefaultLineThickness(); + + pX = m_pos.x + aOffset.x; + pY = m_pos.y + aOffset.y; + + EDA_COLOR_T color; + if( aColor >= 0 ) + color = aColor; + else + color = GetLayerColor( LAYER_NOCONNECT ); + + GRSetDrawMode( aDC, aDrawMode ); + + GRLine( aPanel->GetClipBox(), aDC, pX - delta, pY - delta, pX + delta, pY + delta, + width, color ); + GRLine( aPanel->GetClipBox(), aDC, pX + delta, pY - delta, pX - delta, pY + delta, + width, color ); +} + + +void SCH_NO_CONNECT::MirrorX( int aXaxis_position ) +{ + MIRROR( m_pos.y, aXaxis_position ); +} + + +void SCH_NO_CONNECT::MirrorY( int aYaxis_position ) +{ + MIRROR( m_pos.x, aYaxis_position ); +} + + +void SCH_NO_CONNECT::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_pos, aPosition, 900 ); +} + + +bool SCH_NO_CONNECT::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_pos ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_NO_CONNECT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + aPoints.push_back( m_pos ); +} + + +void SCH_NO_CONNECT::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + + item->m_SheetPath = *aSheetPath; + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = this; + item->m_Type = NET_NOCONNECT; + item->m_Start = item->m_End = m_pos; + + aNetListItems.push_back( item ); +} + + +bool SCH_NO_CONNECT::doIsConnected( const wxPoint& aPosition ) const +{ + return m_pos == aPosition; +} + +bool SCH_NO_CONNECT::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + int delta = ( ( m_size.x + GetDefaultLineThickness() ) / 2 ) + aAccuracy; + + wxPoint dist = aPosition - m_pos; + + if( ( std::abs( dist.x ) <= delta ) && ( std::abs( dist.y ) <= delta ) ) + return true; + + return false; +} + + +bool SCH_NO_CONNECT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +void SCH_NO_CONNECT::Plot( PLOTTER* aPlotter ) +{ + int delta = m_size.x / 2; + int pX, pY; + + pX = m_pos.x; + pY = m_pos.y; + + aPlotter->SetCurrentLineWidth( GetPenSize() ); + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + aPlotter->MoveTo( wxPoint( pX - delta, pY - delta ) ); + aPlotter->FinishTo( wxPoint( pX + delta, pY + delta ) ); + aPlotter->MoveTo( wxPoint( pX + delta, pY - delta ) ); + aPlotter->FinishTo( wxPoint( pX - delta, pY + delta ) ); +} + diff --git a/eeschema/sch_no_connect.h b/eeschema/sch_no_connect.h new file mode 100644 index 00000000..f5663047 --- /dev/null +++ b/eeschema/sch_no_connect.h @@ -0,0 +1,115 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_no_connect.h + */ + +#ifndef _SCH_NO_CONNECT_H_ +#define _SCH_NO_CONNECT_H_ + + +#include + +class NETLIST_OBJECT_LIST; + +class SCH_NO_CONNECT : public SCH_ITEM +{ + wxPoint m_pos; ///< Position of the no connect object. + wxSize m_size; ///< Size of the no connect object. + +public: + SCH_NO_CONNECT( const wxPoint& pos = wxPoint( 0, 0 ) ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_NO_CONNECT() { } + + wxString GetClass() const + { + return wxT( "SCH_NO_CONNECT" ); + } + + int GetPenSize() const; + + void SwapData( SCH_ITEM* aItem ); + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + m_pos += aMoveVector; + } + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const { return true; } + + void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const; + + wxString GetSelectMenuText() const { return wxString( _( "No Connect" ) ); } + + BITMAP_DEF GetMenuImage() const { return noconn_xpm; } + + void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, SCH_SHEET_PATH* aSheetPath ); + + wxPoint GetPosition() const { return m_pos; } + + void SetPosition( const wxPoint& aPosition ) { m_pos = aPosition; } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override +#endif + +private: + bool doIsConnected( const wxPoint& aPosition ) const; +}; + + +#endif // _SCH_NO_CONNECT_H_ diff --git a/eeschema/sch_reference_list.h b/eeschema/sch_reference_list.h new file mode 100644 index 00000000..d5048cbf --- /dev/null +++ b/eeschema/sch_reference_list.h @@ -0,0 +1,469 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2011 jean-pierre Charras + * Copyright (C) 1992-2011 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + + +/** + * @file eeschema/sch_reference_list.h + */ + +#ifndef _SCH_REFERENCE_LIST_H_ +#define _SCH_REFERENCE_LIST_H_ + + +#include + +#include +#include +#include +#include + +#include + +class SCH_REFERENCE; +class SCH_REFERENCE_LIST; + +/** + * Class SCH_REFERENCE + * is used as a helper to define a component's reference designator in a schematic. This + * helper is required in a complex hierarchy because a component can be used more than + * once and its reference depends on the sheet path. This class is used to flatten the + * schematic hierarchy for annotation, net list generation, and bill of material + * generation. + */ +class SCH_REFERENCE +{ + /// Component reference prefix, without number (for IC1, this is IC) ) + UTF8 m_Ref; // it's private, use the accessors please + SCH_COMPONENT* m_RootCmp; ///< The component associated the reference object. + LIB_PART* m_Entry; ///< The source component from a library. + wxPoint m_CmpPos; ///< The physical position of the component in schematic + ///< used to annotate by X or Y position + int m_Unit; ///< The unit number for components with multiple parts + ///< per package. + SCH_SHEET_PATH m_SheetPath; ///< The sheet path for this reference. + bool m_IsNew; ///< True if not yet annotated. + int m_SheetNum; ///< The sheet number for the reference. + time_t m_TimeStamp; ///< The time stamp for the reference. + EDA_TEXT* m_Value; ///< The component value of the refernce. It is the + ///< same for all instances. + int m_NumRef; ///< The numeric part of the reference designator. + int m_Flag; + + friend class SCH_REFERENCE_LIST; + + +public: + + SCH_REFERENCE() : + m_SheetPath() + { + m_RootCmp = NULL; + m_Entry = NULL; + m_Unit = 0; + m_TimeStamp = 0; + m_IsNew = false; + m_Value = NULL; + m_NumRef = 0; + m_Flag = 0; + m_SheetNum = 0; + } + + SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibComponent, + SCH_SHEET_PATH& aSheetPath ); + + SCH_COMPONENT* GetComp() const { return m_RootCmp; } + + LIB_PART* GetLibComponent() const { return m_Entry; } + + SCH_SHEET_PATH GetSheetPath() const { return m_SheetPath; } + + int GetUnit() const { return m_Unit; } + + void SetSheetNumber( int aSheetNumber ) { m_SheetNum = aSheetNumber; } + + /** + * Function Annotate + * updates the annotation of the component according the the current object state. + */ + void Annotate(); + + /** + * Function Split + * attempts to split the reference designator into a name (U) and number (1). If the + * last character is '?' or not a digit, the reference is tagged as not annotated. + * For components with multiple parts per package that are not already annotated, set + * m_Unit to a max value (0x7FFFFFFF). + */ + void Split(); + + /* Some accessors which hide the strategy of how the reference is stored, + thereby making it easy to change that strategy. + */ + + void SetRef( const wxString& aReference ) + { + m_Ref = aReference; + } + + wxString GetRef() const + { + return m_Ref; + } + void SetRefStr( const std::string& aReference ) + { + m_Ref = aReference; + } + const char* GetRefStr() const + { + return m_Ref.c_str(); + } + + int CompareValue( const SCH_REFERENCE& item ) const + { + return Cmp_KEEPCASE( m_Value->GetText(), item.m_Value->GetText() ); + } + + int CompareRef( const SCH_REFERENCE& item ) const + { + return m_Ref.compare( item.m_Ref ); + } + + int CompareLibName( const SCH_REFERENCE& item ) const + { + return Cmp_KEEPCASE( m_RootCmp->GetPartName(), item.m_RootCmp->GetPartName() ); + } + + /** + * Function IsSameInstance + * returns whether this reference refers to the same component instance + * (component and sheet) as another. + */ + bool IsSameInstance( const SCH_REFERENCE& other ) const + { + return GetComp() == other.GetComp() && GetSheetPath().Path() == other.GetSheetPath().Path(); + } + + bool IsUnitsLocked() + { + return m_Entry->UnitsLocked(); + } +}; + + +/** + * Class SCH_REFERENCE_LIST + * is used to create a flattened list of components because in a complex hierarchy, a component + * can be used more than once and its reference designator is dependent on the sheet path for + * the same component. This flattened list is used for netlist generation, BOM generation, + * and schematic annotation. + */ +class SCH_REFERENCE_LIST +{ +private: + std::vector componentFlatList; + +public: + /** Constructor + */ + SCH_REFERENCE_LIST() + { + } + + SCH_REFERENCE& operator[]( int aIndex ) + { + return componentFlatList[ aIndex ]; + } + + /** + * Function GetCount + * @return the number of items in the list + */ + unsigned GetCount() + { + return componentFlatList.size(); + } + + /** + * Function GetItem + * @return the aIdx item + */ + SCH_REFERENCE& GetItem( int aIdx ) + { + return componentFlatList[aIdx]; + } + + /** + * Function AddItem + * adds a SCH_REFERENCE object to the list of references. + * @param aItem - a SCH_REFERENCE item to add + */ + void AddItem( SCH_REFERENCE& aItem ) + { + componentFlatList.push_back( aItem ); + } + + /** + * Function RemoveItem + * removes an item from the list of references. + * + * @param aIndex is the index of the item to be removed. + */ + void RemoveItem( unsigned int aIndex ); + + /** + * Function RemoveSubComponentsFromList + * Remove sub components from the list, when multiples parts per package are + * found in this list. + * Useful to create BOM, when a component must appear only once + */ + void RemoveSubComponentsFromList(); + + /* Sort functions: + * Sort functions are used to sort components for annotation or BOM generation. + * Because sorting depend on we want to do, there are many sort functions. + * Note: + * When creating BOM, components are fully annotated. + * references are something like U3, U5 or R4, R8 + * When annotating, some or all components are not annotated, + * i.e. ref is only U or R, with no number. + */ + + /** + * Function SplitReferences + * attempts to split all reference designators into a name (U) and number (1). If the + * last character is '?' or not a digit, the reference is tagged as not annotated. + * For components with multiple parts per package that are not already annotated, set + * m_Unit to a max value (0x7FFFFFFF). + * @see SCH_REFERENCE::Split() + */ + void SplitReferences() + { + for( unsigned ii = 0; ii < GetCount(); ii++ ) + componentFlatList[ii].Split(); + } + + /** + * function UpdateAnnotation + * Updates the reference components for the schematic project (or the current sheet) + * Note: this function does not calculate the reference numbers stored in m_NumRef + * So, it must be called after calculation of new reference numbers + * @see SCH_REFERENCE::Annotate() + */ + void UpdateAnnotation() + { + /* update the reference numbers */ + for( unsigned ii = 0; ii < GetCount(); ii++ ) + { + componentFlatList[ii].Annotate(); + } + } + + /** + * Function Annotate + * set the reference designators in the list that have not been annotated. + * @param aUseSheetNum Set to true to start annotation for each sheet at the sheet number + * times \a aSheetIntervalId. Otherwise annotate incrementally. + * @param aSheetIntervalId The per sheet reference designator multiplier. + * @param aLockedUnitMap A SCH_MULTI_UNIT_REFERENCE_MAP of reference designator wxStrings + * to SCH_REFERENCE_LISTs. May be an empty map. If not empty, any multi-unit parts + * found in this map will be annotated as a group rather than individually. + *

      + * If a the sheet number is 2 and \a aSheetIntervalId is 100, then the first reference + * designator would be 201 and the last reference designator would be 299 when no overlap + * occurs with sheet number 3. If there are 150 items in sheet number 2, then items are + * referenced U201 to U351, and items in sheet 3 start from U352 + *

      + */ + void Annotate( bool aUseSheetNum, int aSheetIntervalId, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap ); + + /** + * Function CheckAnnotation + * check for annotations errors. + *

      + * The following annotation error conditions are tested: + *

        + *
      • Components not annotated.
      • + *
      • Components having the same reference designator (duplicates).
      • + *
      • Components with multiple parts per package having different reference designators.
      • + *
      • Components with multiple parts per package with invalid part count.
      • + *
      + *

      + * @param aMessageList A wxArrayString to store error messages. + * @return The number of errors found. + */ + int CheckAnnotation( wxArrayString* aMessageList ); + + /** + * Function sortByXCoordinate + * sorts the list of references by X position. + *

      + * Components are sorted as follows: + *

        + *
      • Numeric value of reference designator.
      • + *
      • Sheet number.
      • + *
      • X coordinate position.
      • + *
      • Y coordinate position.
      • + *
      • Time stamp.
      • + *
      + *

      + */ + void SortByXCoordinate() + { + sort( componentFlatList.begin(), componentFlatList.end(), sortByXPosition ); + } + + /** + * Function sortByYCoordinate + * sorts the list of references by Y position. + *

      + * Components are sorted as follows: + *

        + *
      • Numeric value of reference designator.
      • + *
      • Sheet number.
      • + *
      • Y coordinate position.
      • + *
      • X coordinate position.
      • + *
      • Time stamp.
      • + *
      + *

      + */ + void SortByYCoordinate() + { + sort( componentFlatList.begin(), componentFlatList.end(), sortByYPosition ); + } + + /** + * Function SortComponentsByTimeStamp + * sort the flat list by Time Stamp. + * Useful to detect duplicate Time Stamps + */ + void SortByTimeStamp() + { + sort( componentFlatList.begin(), componentFlatList.end(), sortByTimeStamp ); + } + + /** + * Function SortByRefAndValue + * sorts the list of references by value. + *

      + * Components are sorted in the following order: + *

        + *
      • Numeric value of reference designator.
      • + *
      • Value of component.
      • + *
      • Unit number when component has multiple parts.
      • + *
      • Sheet number.
      • + *
      • X coordinate position.
      • + *
      • Y coordinate position.
      • + *
      + *

      + */ + void SortByRefAndValue() + { + sort( componentFlatList.begin(), componentFlatList.end(), sortByRefAndValue ); + } + + /** + * Function SortByReferenceOnly + * sorts the list of references by reference. + *

      + * Components are sorted in the following order: + *

        + *
      • Numeric value of reference designator.
      • + *
      • Unit number when component has multiple parts.
      • + *
      + *

      + */ + void SortByReferenceOnly() + { + sort( componentFlatList.begin(), componentFlatList.end(), sortByReferenceOnly ); + } + + /** + * Function GetUnit + * searches the sorted list of components for a another component with the same + * reference and a given part unit. Use this method to manage components with + * multiple parts per package. + * @param aIndex = index in aComponentsList for of given SCH_REFERENCE item to test. + * @param aUnit = the given unit number to search + * @return index in aComponentsList if found or -1 if not found + */ + int FindUnit( size_t aIndex, int aUnit ); + + /** + * Function ResetHiddenReferences + * clears the annotation for all references that have an invisible reference designator. + * Invisible reference designators always have # as the first letter. + */ + void ResetHiddenReferences(); + + /** + * Function GetRefsInUse + * adds all the reference designator numbers greater than \a aMinRefId to \a aIdList + * skipping the reference at \a aIndex. + * @param aIndex = the current component index to use for reference prefix filtering. + * @param aIdList = the buffer to fill + * @param aMinRefId = the min id value to store. all values < aMinRefId are ignored + */ + void GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId ); + + /** + * Function GetLastReference + * returns the last used (greatest) reference number in the reference list + * for the prefix reference given by \a aIndex. The component list must be + * sorted. + * + * @param aIndex The index of the reference item used for the search pattern. + * @param aMinValue The minimum value for the current search. + */ + int GetLastReference( int aIndex, int aMinValue ); + +private: + /* sort functions used to sort componentFlatList + */ + + static bool sortByRefAndValue( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + static bool sortByXPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + static bool sortByYPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + static bool sortByTimeStamp( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + static bool sortByReferenceOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); + + /** + * Function CreateFirstFreeRefId + * searches for the first free reference number in \a aListId of reference numbers in use. + * This function just searches for a hole in a list of incremented numbers, this list must + * be sorted by increasing values and each value can be stored only once. The new value + * is added to the list. + * @see BuildRefIdInUseList to prepare this list + * @param aIdList The buffer that contains the reference numbers in use. + * @param aFirstValue The first expected free value + * @return The first free (not yet used) value. + */ + int CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ); +}; + +#endif // _SCH_REFERENCE_LIST_H_ diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp new file mode 100644 index 00000000..c2f82019 --- /dev/null +++ b/eeschema/sch_screen.cpp @@ -0,0 +1,1563 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2008-2015 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_screen.cpp + * @brief Implementation of SCH_SCREEN and SCH_SCREENS classes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EESCHEMA_FILE_STAMP "EESchema" + +/* Default zoom values. Limited to these values to keep a decent size + * to menus + */ +static double SchematicZoomList[] = +{ + 0.5, 0.7, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 11.0, + 13.0, 16.0, 20.0, 26.0, 32.0, 48.0, 64.0, 80.0, 128.0 +}; + +#define MM_TO_SCH_UNITS 1000.0 / 25.4 //schematic internal unites are mils + + +/* Default grid sizes for the schematic editor. + * Do NOT add others values (mainly grid values in mm), because they + * can break the schematic: Because wires and pins are considered as + * connected when the are to the same coordinate we cannot mix + * coordinates in mils (internal units) and mm (that cannot exactly + * converted in mils in many cases). In fact schematic must only use + * 50 and 25 mils to place labels, wires and components others values + * are useful only for graphic items (mainly in library editor) so use + * integer values in mils only. The 100 mil grid is added to help + * conform to the KiCad Library Convention. Which states: "Using a + * 100mil grid, pin ends and origin must lie on grid nodes IEC-60617" +*/ +static GRID_TYPE SchematicGridList[] = { + { ID_POPUP_GRID_LEVEL_100, wxRealPoint( 100, 100 ) }, + { ID_POPUP_GRID_LEVEL_50, wxRealPoint( 50, 50 ) }, + { ID_POPUP_GRID_LEVEL_25, wxRealPoint( 25, 25 ) }, + { ID_POPUP_GRID_LEVEL_10, wxRealPoint( 10, 10 ) }, + { ID_POPUP_GRID_LEVEL_5, wxRealPoint( 5, 5 ) }, + { ID_POPUP_GRID_LEVEL_2, wxRealPoint( 2, 2 ) }, + { ID_POPUP_GRID_LEVEL_1, wxRealPoint( 1, 1 ) }, +}; + + +SCH_SCREEN::SCH_SCREEN( KIWAY* aKiway ) : + BASE_SCREEN( SCH_SCREEN_T ), + KIWAY_HOLDER( aKiway ), + m_paper( wxT( "A4" ) ) +{ + m_modification_sync = 0; + + SetZoom( 32 ); + + for( unsigned i = 0; i < DIM( SchematicZoomList ); i++ ) + m_ZoomList.push_back( SchematicZoomList[i] ); + + for( unsigned i = 0; i < DIM( SchematicGridList ); i++ ) + AddGrid( SchematicGridList[i] ); + + SetGrid( wxRealPoint( 50, 50 ) ); // Default grid size. + m_refCount = 0; + + // Suitable for schematic only. For libedit and viewlib, must be set to true + m_Center = false; + + InitDataPoints( m_paper.GetSizeIU() ); +} + + +SCH_SCREEN::~SCH_SCREEN() +{ + ClearUndoRedoList(); + FreeDrawList(); +} + + +void SCH_SCREEN::IncRefCount() +{ + m_refCount++; +} + + +void SCH_SCREEN::DecRefCount() +{ + wxCHECK_RET( m_refCount != 0, + wxT( "Screen reference count already zero. Bad programmer!" ) ); + m_refCount--; +} + + +void SCH_SCREEN::Clear() +{ + FreeDrawList(); + + // Clear the project settings + m_ScreenNumber = m_NumberOfScreens = 1; + + m_titles.Clear(); +} + + +void SCH_SCREEN::FreeDrawList() +{ + m_drawList.DeleteAll(); +} + + +void SCH_SCREEN::Remove( SCH_ITEM* aItem ) +{ + m_drawList.Remove( aItem ); +} + + +void SCH_SCREEN::DeleteItem( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem, wxT( "Cannot delete invalid item from screen." ) ); + + SetModify(); + + if( aItem->Type() == SCH_SHEET_PIN_T ) + { + // This structure is attached to a sheet, get the parent sheet object. + SCH_SHEET_PIN* sheetPin = (SCH_SHEET_PIN*) aItem; + SCH_SHEET* sheet = sheetPin->GetParent(); + wxCHECK_RET( sheet, + wxT( "Sheet label parent not properly set, bad programmer!" ) ); + sheet->RemovePin( sheetPin ); + return; + } + else + { + delete m_drawList.Remove( aItem ); + } +} + + +bool SCH_SCREEN::CheckIfOnDrawList( SCH_ITEM* aItem ) +{ + SCH_ITEM* itemList = m_drawList.begin(); + + while( itemList ) + { + if( itemList == aItem ) + return true; + + itemList = itemList->Next(); + } + + return false; +} + + +SCH_ITEM* SCH_SCREEN::GetItem( const wxPoint& aPosition, int aAccuracy, KICAD_T aType ) const +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->HitTest( aPosition, aAccuracy ) && (aType == NOT_USED) ) + return item; + + if( (aType == SCH_FIELD_T) && (item->Type() == SCH_COMPONENT_T) ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + for( int i = REFERENCE; i < component->GetFieldCount(); i++ ) + { + SCH_FIELD* field = component->GetField( i ); + + if( field->HitTest( aPosition, aAccuracy ) ) + return (SCH_ITEM*) field; + } + } + else if( (aType == SCH_SHEET_PIN_T) && (item->Type() == SCH_SHEET_T) ) + { + SCH_SHEET* sheet = (SCH_SHEET*)item; + + SCH_SHEET_PIN* label = sheet->GetPin( aPosition ); + + if( label ) + return (SCH_ITEM*) label; + } + else if( (item->Type() == aType) && item->HitTest( aPosition, aAccuracy ) ) + { + return item; + } + } + + return NULL; +} + + +void SCH_SCREEN::ExtractWires( DLIST< SCH_ITEM >& aList, bool aCreateCopy ) +{ + SCH_ITEM* item; + SCH_ITEM* next_item; + + for( item = m_drawList.begin(); item; item = next_item ) + { + next_item = item->Next(); + + switch( item->Type() ) + { + case SCH_JUNCTION_T: + case SCH_LINE_T: + m_drawList.Remove( item ); + aList.Append( item ); + + if( aCreateCopy ) + m_drawList.Insert( (SCH_ITEM*) item->Clone(), next_item ); + + break; + + default: + break; + } + } +} + + +void SCH_SCREEN::ReplaceWires( DLIST< SCH_ITEM >& aWireList ) +{ + SCH_ITEM* item; + SCH_ITEM* next_item; + + for( item = m_drawList.begin(); item; item = next_item ) + { + next_item = item->Next(); + + switch( item->Type() ) + { + case SCH_JUNCTION_T: + case SCH_LINE_T: + Remove( item ); + delete item; + break; + + default: + break; + } + } + + m_drawList.Append( aWireList ); +} + + +void SCH_SCREEN::MarkConnections( SCH_LINE* aSegment ) +{ + wxCHECK_RET( (aSegment) && (aSegment->Type() == SCH_LINE_T), + wxT( "Invalid object pointer." ) ); + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->GetFlags() & CANDIDATE ) + continue; + + if( item->Type() == SCH_JUNCTION_T ) + { + SCH_JUNCTION* junction = (SCH_JUNCTION*) item; + + if( aSegment->IsEndPoint( junction->GetPosition() ) ) + item->SetFlags( CANDIDATE ); + + continue; + } + + if( item->Type() != SCH_LINE_T ) + continue; + + SCH_LINE* segment = (SCH_LINE*) item; + + if( aSegment->IsEndPoint( segment->GetStartPoint() ) + && !GetPin( segment->GetStartPoint(), NULL, true ) ) + { + item->SetFlags( CANDIDATE ); + MarkConnections( segment ); + } + + if( aSegment->IsEndPoint( segment->GetEndPoint() ) + && !GetPin( segment->GetEndPoint(), NULL, true ) ) + { + item->SetFlags( CANDIDATE ); + MarkConnections( segment ); + } + } +} + + +bool SCH_SCREEN::IsJunctionNeeded( const wxPoint& aPosition ) +{ + if( GetItem( aPosition, 0, SCH_JUNCTION_T ) ) + return false; + + if( GetWire( aPosition, 0, EXCLUDE_END_POINTS_T ) ) + { + if( GetWire( aPosition, 0, END_POINTS_ONLY_T ) ) + return true; + + if( GetPin( aPosition, NULL, true ) ) + return true; + } + + return false; +} + + +bool SCH_SCREEN::IsTerminalPoint( const wxPoint& aPosition, int aLayer ) +{ + wxCHECK_MSG( aLayer == LAYER_NOTES || aLayer == LAYER_BUS || aLayer == LAYER_WIRE, false, + wxT( "Invalid layer type passed to SCH_SCREEN::IsTerminalPoint()." ) ); + + SCH_SHEET_PIN* label; + SCH_TEXT* text; + + switch( aLayer ) + { + case LAYER_BUS: + + if( GetBus( aPosition ) ) + return true; + + label = GetSheetLabel( aPosition ); + + if( label && IsBusLabel( label->GetText() ) && label->IsConnected( aPosition ) ) + return true; + + text = GetLabel( aPosition ); + + if( text && IsBusLabel( text->GetText() ) && text->IsConnected( aPosition ) + && (text->Type() != SCH_LABEL_T) ) + return true; + + break; + + case LAYER_NOTES: + + if( GetLine( aPosition ) ) + return true; + + break; + + case LAYER_WIRE: + if( GetItem( aPosition, std::max( GetDefaultLineThickness(), 3 ), SCH_BUS_WIRE_ENTRY_T) ) + return true; + + if( GetItem( aPosition, std::max( GetDefaultLineThickness(), 3 ), SCH_BUS_BUS_ENTRY_T) ) + return true; + + if( GetItem( aPosition, std::max( GetDefaultLineThickness(), 3 ), SCH_JUNCTION_T ) ) + return true; + + if( GetPin( aPosition, NULL, true ) ) + return true; + + if( GetWire( aPosition ) ) + return true; + + text = GetLabel( aPosition ); + + if( text && text->IsConnected( aPosition ) && !IsBusLabel( text->GetText() ) ) + return true; + + label = GetSheetLabel( aPosition ); + + if( label && label->IsConnected( aPosition ) && !IsBusLabel( label->GetText() ) ) + return true; + + break; + + default: + break; + } + + return false; +} + + +bool SCH_SCREEN::SchematicCleanUp( EDA_DRAW_PANEL* aCanvas, wxDC* aDC ) +{ + SCH_ITEM* item, * testItem; + bool modified = false; + + item = m_drawList.begin(); + + for( ; item; item = item->Next() ) + { + if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) + continue; + + testItem = item->Next(); + + while( testItem ) + { + if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) ) + { + SCH_LINE* line = (SCH_LINE*) item; + + if( line->MergeOverlap( (SCH_LINE*) testItem ) ) + { + // Keep the current flags, because the deleted segment can be flagged. + item->SetFlags( testItem->GetFlags() ); + DeleteItem( testItem ); + testItem = m_drawList.begin(); + modified = true; + } + else + { + testItem = testItem->Next(); + } + } + else if ( ( ( item->Type() == SCH_JUNCTION_T ) && ( testItem->Type() == SCH_JUNCTION_T ) ) && ( testItem != item ) ) + { + if ( testItem->HitTest( item->GetPosition() ) ) + { + // Keep the current flags, because the deleted segment can be flagged. + item->SetFlags( testItem->GetFlags() ); + DeleteItem( testItem ); + testItem = m_drawList.begin(); + modified = true; + } + else + { + testItem = testItem->Next(); + } + } + else + { + testItem = testItem->Next(); + } + } + } + + TestDanglingEnds( aCanvas, aDC ); + + if( aCanvas && modified ) + aCanvas->Refresh(); + + return modified; +} + + +bool SCH_SCREEN::Save( FILE* aFile ) const +{ + // Creates header + if( fprintf( aFile, "%s %s %d\n", EESCHEMA_FILE_STAMP, + SCHEMATIC_HEAD_STRING, EESCHEMA_VERSION ) < 0 ) + return false; + + BOOST_FOREACH( const PART_LIB& lib, *Prj().SchLibs() ) + { + if( fprintf( aFile, "LIBS:%s\n", TO_UTF8( lib.GetName() ) ) < 0 ) + return false; + } + + // This section is not used, but written for file compatibility + if( fprintf( aFile, "EELAYER %d %d\n", LAYERSCH_ID_COUNT, 0 ) < 0 + || fprintf( aFile, "EELAYER END\n" ) < 0 ) + return false; + + /* Write page info, ScreenNumber and NumberOfScreen; not very meaningful for + * SheetNumber and Sheet Count in a complex hierarchy, but useful in + * simple hierarchy and flat hierarchy. Used also to search the root + * sheet ( ScreenNumber = 1 ) within the files + */ + const TITLE_BLOCK& tb = GetTitleBlock(); + + if( fprintf( aFile, "$Descr %s %d %d%s\n", TO_UTF8( m_paper.GetType() ), + m_paper.GetWidthMils(), + m_paper.GetHeightMils(), + !m_paper.IsCustom() && m_paper.IsPortrait() ? + " portrait" : "" + ) < 0 + || fprintf( aFile, "encoding utf-8\n") < 0 + || fprintf( aFile, "Sheet %d %d\n", m_ScreenNumber, m_NumberOfScreens ) < 0 + || fprintf( aFile, "Title %s\n", EscapedUTF8( tb.GetTitle() ).c_str() ) < 0 + || fprintf( aFile, "Date %s\n", EscapedUTF8( tb.GetDate() ).c_str() ) < 0 + || fprintf( aFile, "Rev %s\n", EscapedUTF8( tb.GetRevision() ).c_str() ) < 0 + || fprintf( aFile, "Comp %s\n", EscapedUTF8( tb.GetCompany() ).c_str() ) < 0 + || fprintf( aFile, "Comment1 %s\n", EscapedUTF8( tb.GetComment1() ).c_str() ) < 0 + || fprintf( aFile, "Comment2 %s\n", EscapedUTF8( tb.GetComment2() ).c_str() ) < 0 + || fprintf( aFile, "Comment3 %s\n", EscapedUTF8( tb.GetComment3() ).c_str() ) < 0 + || fprintf( aFile, "Comment4 %s\n", EscapedUTF8( tb.GetComment4() ).c_str() ) < 0 + || fprintf( aFile, "$EndDescr\n" ) < 0 ) + return false; + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( !item->Save( aFile ) ) + return false; + } + + if( fprintf( aFile, "$EndSCHEMATC\n" ) < 0 ) + return false; + + return true; +} + + +void SCH_SCREEN::CheckComponentsToPartsLinks() +{ + // Initialize or reinitialize the pointer to the LIB_PART for each component + // found in m_drawList, but only if needed (change in lib or schematic) + // therefore the calculation time is usually very low. + + if( m_drawList.GetCount() ) + { + PART_LIBS* libs = Prj().SchLibs(); + int mod_hash = libs->GetModifyHash(); + + // Must we resolve? + if( m_modification_sync != mod_hash ) + { + SCH_TYPE_COLLECTOR c; + + c.Collect( GetDrawItems(), SCH_COLLECTOR::ComponentsOnly ); + + SCH_COMPONENT::ResolveAll( c, libs ); + + m_modification_sync = mod_hash; // note the last mod_hash + + // guard against unneeded runs through this code path by printing trace + DBG(printf("%s: resync-ing %s\n", __func__, TO_UTF8( GetFileName() ) );) + } + } +} + + +void SCH_SCREEN::Draw( EDA_DRAW_PANEL* aCanvas, wxDC* aDC, GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + /* note: SCH_SCREEN::Draw is useful only for schematic. + * library editor and library viewer do not use m_drawList, and therefore + * their SCH_SCREEN::Draw() draws nothing + */ + + CheckComponentsToPartsLinks(); + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->IsMoving() || item->IsResized() ) + continue; + + // uncomment line below when there is a virtual + // EDA_ITEM::GetBoundingBox() + // if( panel->GetClipBox().Intersects( Structs->GetBoundingBox() + // ) ) + item->Draw( aCanvas, aDC, wxPoint( 0, 0 ), aDrawMode, aColor ); + } +} + + +/* note: SCH_SCREEN::Plot is useful only for schematic. + * library editor and library viewer do not use a draw list, and therefore + * SCH_SCREEN::Plot plots nothing + */ +void SCH_SCREEN::Plot( PLOTTER* aPlotter ) +{ + CheckComponentsToPartsLinks(); + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + aPlotter->SetCurrentLineWidth( item->GetPenSize() ); + item->Plot( aPlotter ); + } +} + + +void SCH_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount ) +{ + if( aItemCount == 0 ) + return; + + unsigned icnt = aList.m_CommandsList.size(); + + if( aItemCount > 0 ) + icnt = aItemCount; + + for( unsigned ii = 0; ii < icnt; ii++ ) + { + if( aList.m_CommandsList.size() == 0 ) + break; + + PICKED_ITEMS_LIST* curr_cmd = aList.m_CommandsList[0]; + aList.m_CommandsList.erase( aList.m_CommandsList.begin() ); + + curr_cmd->ClearListAndDeleteItems(); + delete curr_cmd; // Delete command + } +} + + +void SCH_SCREEN::ClearDrawingState() +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + item->ClearFlags(); +} + + +LIB_PIN* SCH_SCREEN::GetPin( const wxPoint& aPosition, SCH_COMPONENT** aComponent, + bool aEndPointOnly ) const +{ + SCH_ITEM* item; + SCH_COMPONENT* component = NULL; + LIB_PIN* pin = NULL; + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + component = (SCH_COMPONENT*) item; + + if( aEndPointOnly ) + { + pin = NULL; + + LIB_PART* part = Prj().SchLibs()->FindLibPart( component->GetPartName() ); + + if( !part ) + continue; + + for( pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) + { + // Skip items not used for this part. + if( component->GetUnit() && pin->GetUnit() && + ( pin->GetUnit() != component->GetUnit() ) ) + continue; + + if( component->GetConvert() && pin->GetConvert() && + ( pin->GetConvert() != component->GetConvert() ) ) + continue; + + if(component->GetPinPhysicalPosition( pin ) == aPosition ) + break; + } + if( pin ) + break; + } + else + { + pin = (LIB_PIN*) component->GetDrawItem( aPosition, LIB_PIN_T ); + + if( pin ) + break; + } + } + + if( pin && aComponent ) + *aComponent = component; + + return pin; +} + + +SCH_SHEET* SCH_SCREEN::GetSheet( const wxString& aName ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() != SCH_SHEET_T ) + continue; + + SCH_SHEET* sheet = (SCH_SHEET*) item; + + if( aName.CmpNoCase( sheet->GetName() ) == 0 ) + return sheet; + } + + return NULL; +} + + +SCH_SHEET_PIN* SCH_SCREEN::GetSheetLabel( const wxPoint& aPosition ) +{ + SCH_SHEET_PIN* sheetPin = NULL; + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() != SCH_SHEET_T ) + continue; + + SCH_SHEET* sheet = (SCH_SHEET*) item; + sheetPin = sheet->GetPin( aPosition ); + + if( sheetPin ) + break; + } + + return sheetPin; +} + + +int SCH_SCREEN::CountConnectedItems( const wxPoint& aPos, bool aTestJunctions ) const +{ + SCH_ITEM* item; + int count = 0; + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() == SCH_JUNCTION_T && !aTestJunctions ) + continue; + + if( item->IsConnected( aPos ) ) + count++; + } + + return count; +} + + +void SCH_SCREEN::ClearAnnotation( SCH_SHEET_PATH* aSheetPath ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() == SCH_COMPONENT_T ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + component->ClearAnnotation( aSheetPath ); + + // Clear the modified component flag set by component->ClearAnnotation + // because we do not use it here and we should not leave this flag set, + // when an edition is finished: + component->ClearFlags(); + } + } +} + + +void SCH_SCREEN::GetHierarchicalItems( EDA_ITEMS& aItems ) +{ + SCH_ITEM* item = m_drawList.begin(); + + while( item ) + { + if( ( item->Type() == SCH_SHEET_T ) || ( item->Type() == SCH_COMPONENT_T ) ) + aItems.push_back( item ); + + item = item->Next(); + } +} + + +void SCH_SCREEN::SelectBlockItems() +{ + PICKED_ITEMS_LIST* pickedlist = &m_BlockLocate.GetItems(); + + if( pickedlist->GetCount() == 0 ) + return; + + ClearDrawingState(); + + for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) pickedlist->GetPickedItem( ii ); + item->SetFlags( SELECTED ); + } + + if( !m_BlockLocate.IsDragging() ) + return; + + // Select all the items in the screen connected to the items in the block. + // be sure end lines that are on the block limits are seen inside this block + m_BlockLocate.Inflate( 1 ); + unsigned last_select_id = pickedlist->GetCount(); + + for( unsigned ii = 0; ii < last_select_id; ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*)pickedlist->GetPickedItem( ii ); + item->SetFlags( IS_DRAGGED ); + + if( item->Type() == SCH_LINE_T ) + { + item->IsSelectStateChanged( m_BlockLocate ); + + if( !item->IsSelected() ) + { // This is a special case: + // this selected wire has no ends in block. + // But it was selected (because it intersects the selecting area), + // so we must keep it selected and select items connected to it + // Note: an other option could be: remove it from drag list + item->SetFlags( SELECTED | SKIP_STRUCT ); + std::vector< wxPoint > connections; + item->GetConnectionPoints( connections ); + + for( size_t i = 0; i < connections.size(); i++ ) + addConnectedItemsToBlock( connections[i] ); + } + + pickedlist->SetPickerFlags( item->GetFlags(), ii ); + } + else if( item->IsConnectable() ) + { + std::vector< wxPoint > connections; + + item->GetConnectionPoints( connections ); + + for( size_t jj = 0; jj < connections.size(); jj++ ) + addConnectedItemsToBlock( connections[jj] ); + } + } + + m_BlockLocate.Inflate( -1 ); +} + + +void SCH_SCREEN::addConnectedItemsToBlock( const wxPoint& position ) +{ + SCH_ITEM* item; + ITEM_PICKER picker; + bool addinlist = true; + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + picker.SetItem( item ); + + if( !item->IsConnectable() || !item->IsConnected( position ) + || (item->GetFlags() & SKIP_STRUCT) ) + continue; + + if( item->IsSelected() && item->Type() != SCH_LINE_T ) + continue; + + // A line having 2 ends, it can be tested twice: one time per end + if( item->Type() == SCH_LINE_T ) + { + if( ! item->IsSelected() ) // First time this line is tested + item->SetFlags( SELECTED | STARTPOINT | ENDPOINT ); + else // second time (or more) this line is tested + addinlist = false; + + SCH_LINE* line = (SCH_LINE*) item; + + if( line->GetStartPoint() == position ) + item->ClearFlags( STARTPOINT ); + else if( line->GetEndPoint() == position ) + item->ClearFlags( ENDPOINT ); + } + else + item->SetFlags( SELECTED ); + + if( addinlist ) + { + picker.SetFlags( item->GetFlags() ); + m_BlockLocate.GetItems().PushItem( picker ); + } + } +} + + +int SCH_SCREEN::UpdatePickList() +{ + ITEM_PICKER picker; + EDA_RECT area; + unsigned count; + + area.SetOrigin( m_BlockLocate.GetOrigin() ); + area.SetSize( m_BlockLocate.GetSize() ); + area.Normalize(); + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + // An item is picked if its bounding box intersects the reference area. + if( item->HitTest( area ) ) + { + picker.SetItem( item ); + m_BlockLocate.PushItem( picker ); + } + } + + // if the block is composed of one item, + // select it as the current item + count = m_BlockLocate.GetCount(); + if( count == 1 ) + { + SetCurItem( (SCH_ITEM*) m_BlockLocate.GetItem( 0 ) ); + } + else + { + SetCurItem( NULL ); + } + + return count; +} + + +bool SCH_SCREEN::TestDanglingEnds( EDA_DRAW_PANEL* aCanvas, wxDC* aDC ) +{ + SCH_ITEM* item; + std::vector< DANGLING_END_ITEM > endPoints; + bool hasDanglingEnds = false; + + for( item = m_drawList.begin(); item; item = item->Next() ) + item->GetEndPoints( endPoints ); + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->IsDanglingStateChanged( endPoints ) && ( aCanvas ) && ( aDC ) ) + { + item->Draw( aCanvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + item->Draw( aCanvas, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + } + + if( item->IsDangling() ) + hasDanglingEnds = true; + } + + return hasDanglingEnds; +} + + +bool SCH_SCREEN::BreakSegment( const wxPoint& aPoint ) +{ + SCH_LINE* segment; + SCH_LINE* newSegment; + bool brokenSegments = false; + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( (item->Type() != SCH_LINE_T) || (item->GetLayer() == LAYER_NOTES) ) + continue; + + segment = (SCH_LINE*) item; + + if( !segment->HitTest( aPoint, 0 ) || segment->IsEndPoint( aPoint ) ) + continue; + + // Break the segment at aPoint and create a new segment. + newSegment = new SCH_LINE( *segment ); + newSegment->SetStartPoint( aPoint ); + segment->SetEndPoint( aPoint ); + m_drawList.Insert( newSegment, segment->Next() ); + item = newSegment; + brokenSegments = true; + } + + return brokenSegments; +} + + +bool SCH_SCREEN::BreakSegmentsOnJunctions() +{ + bool brokenSegments = false; + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() == SCH_JUNCTION_T ) + { + SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item; + + if( BreakSegment( junction->GetPosition() ) ) + brokenSegments = true; + } + else + { + SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast( item ); + if( busEntry ) + { + if( BreakSegment( busEntry->GetPosition() ) + || BreakSegment( busEntry->m_End() ) ) + brokenSegments = true; + } + } + } + + return brokenSegments; +} + + +int SCH_SCREEN::GetNode( const wxPoint& aPosition, EDA_ITEMS& aList ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() == SCH_LINE_T && item->HitTest( aPosition ) + && (item->GetLayer() == LAYER_BUS || item->GetLayer() == LAYER_WIRE) ) + { + aList.push_back( item ); + } + else if( item->Type() == SCH_JUNCTION_T && item->HitTest( aPosition ) ) + { + aList.push_back( item ); + } + } + + return (int) aList.size(); +} + + +SCH_LINE* SCH_SCREEN::GetWireOrBus( const wxPoint& aPosition ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( (item->Type() == SCH_LINE_T) && item->HitTest( aPosition ) + && (item->GetLayer() == LAYER_BUS || item->GetLayer() == LAYER_WIRE) ) + { + return (SCH_LINE*) item; + } + } + + return NULL; +} + + +SCH_LINE* SCH_SCREEN::GetLine( const wxPoint& aPosition, int aAccuracy, int aLayer, + SCH_LINE_TEST_T aSearchType ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() != SCH_LINE_T ) + continue; + + if( item->GetLayer() != aLayer ) + continue; + + if( !item->HitTest( aPosition, aAccuracy ) ) + continue; + + switch( aSearchType ) + { + case ENTIRE_LENGTH_T: + return (SCH_LINE*) item; + + case EXCLUDE_END_POINTS_T: + if( !( (SCH_LINE*) item )->IsEndPoint( aPosition ) ) + return (SCH_LINE*) item; + break; + + case END_POINTS_ONLY_T: + if( ( (SCH_LINE*) item )->IsEndPoint( aPosition ) ) + return (SCH_LINE*) item; + } + } + + return NULL; +} + + +SCH_TEXT* SCH_SCREEN::GetLabel( const wxPoint& aPosition, int aAccuracy ) +{ + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + switch( item->Type() ) + { + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + if( item->HitTest( aPosition, aAccuracy ) ) + return (SCH_TEXT*) item; + + default: + ; + } + } + + return NULL; +} + + +bool SCH_SCREEN::SetComponentFootprint( SCH_SHEET_PATH* aSheetPath, const wxString& aReference, + const wxString& aFootPrint, bool aSetVisible ) +{ + SCH_COMPONENT* component; + bool found = false; + + for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + component = (SCH_COMPONENT*) item; + + if( aReference.CmpNoCase( component->GetRef( aSheetPath ) ) == 0 ) + { + // Found: Init Footprint Field + + /* Give a reasonable value to the field position and + * orientation, if the text is empty at position 0, because + * it is probably not yet initialized + */ + SCH_FIELD * fpfield = component->GetField( FOOTPRINT ); + if( fpfield->GetText().IsEmpty() + && ( fpfield->GetTextPosition() == component->GetPosition() ) ) + { + fpfield->SetOrientation( component->GetField( VALUE )->GetOrientation() ); + fpfield->SetTextPosition( component->GetField( VALUE )->GetTextPosition() ); + fpfield->SetSize( component->GetField( VALUE )->GetSize() ); + + if( fpfield->GetOrientation() == 0 ) + fpfield->Offset( wxPoint( 0, 100 ) ); + else + fpfield->Offset( wxPoint( 100, 0 ) ); + } + + fpfield->SetText( aFootPrint ); + fpfield->SetVisible( aSetVisible ); + + found = true; + } + } + + return found; +} + + +int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList, + bool aFullConnection ) +{ + SCH_ITEM* item; + EDA_ITEM* tmp; + EDA_ITEMS list; + + // Clear flags member for all items. + ClearDrawingState(); + BreakSegmentsOnJunctions(); + + if( GetNode( aPosition, list ) == 0 ) + return 0; + + for( size_t i = 0; i < list.size(); i++ ) + { + item = (SCH_ITEM*) list[ i ]; + item->SetFlags( SELECTEDNODE | STRUCT_DELETED ); + + /* Put this structure in the picked list: */ + ITEM_PICKER picker( item, UR_DELETED ); + aList.PushItem( picker ); + } + + // Mark all wires, junctions, .. connected to the item(s) found. + if( aFullConnection ) + { + SCH_LINE* segment; + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( !(item->GetFlags() & SELECTEDNODE) ) + continue; + + if( item->Type() != SCH_LINE_T ) + continue; + + MarkConnections( (SCH_LINE*) item ); + } + + // Search all attached wires (i.e wire with one new dangling end ) + for( item = m_drawList.begin(); item; item = item->Next() ) + { + bool noconnect = false; + + if( item->GetFlags() & STRUCT_DELETED ) + continue; // Already seen + + if( !(item->GetFlags() & CANDIDATE) ) + continue; // not a candidate + + if( item->Type() != SCH_LINE_T ) + continue; + + item->SetFlags( SKIP_STRUCT ); + + segment = (SCH_LINE*) item; + + /* If the wire start point is connected to a wire that was already found + * and now is not connected, add the wire to the list. */ + for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) + { + // Ensure tmp is a previously deleted segment: + if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) + continue; + + if( tmp->Type() != SCH_LINE_T ) + continue; + + SCH_LINE* testSegment = (SCH_LINE*) tmp; + + // Test for segment connected to the previously deleted segment: + if( testSegment->IsEndPoint( segment->GetStartPoint() ) ) + break; + } + + // when tmp != NULL, segment is a new candidate: + // put it in deleted list if + // the start point is not connected to an other item (like pin) + if( tmp && !CountConnectedItems( segment->GetStartPoint(), true ) ) + noconnect = true; + + /* If the wire end point is connected to a wire that has already been found + * and now is not connected, add the wire to the list. */ + for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) + { + // Ensure tmp is a previously deleted segment: + if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) + continue; + + if( tmp->Type() != SCH_LINE_T ) + continue; + + SCH_LINE* testSegment = (SCH_LINE*) tmp; + + // Test for segment connected to the previously deleted segment: + if( testSegment->IsEndPoint( segment->GetEndPoint() ) ) + break; + } + + // when tmp != NULL, segment is a new candidate: + // put it in deleted list if + // the end point is not connected to an other item (like pin) + if( tmp && !CountConnectedItems( segment->GetEndPoint(), true ) ) + noconnect = true; + + item->ClearFlags( SKIP_STRUCT ); + + if( noconnect ) + { + item->SetFlags( STRUCT_DELETED ); + + ITEM_PICKER picker( item, UR_DELETED ); + aList.PushItem( picker ); + + item = m_drawList.begin(); + } + } + + // Get redundant junctions (junctions which connect < 3 end wires + // and no pin) + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->GetFlags() & STRUCT_DELETED ) + continue; + + if( !(item->GetFlags() & CANDIDATE) ) + continue; + + if( item->Type() != SCH_JUNCTION_T ) + continue; + + SCH_JUNCTION* junction = (SCH_JUNCTION*) item; + + if( CountConnectedItems( junction->GetPosition(), false ) <= 2 ) + { + item->SetFlags( STRUCT_DELETED ); + + ITEM_PICKER picker( item, UR_DELETED ); + aList.PushItem( picker ); + } + } + + for( item = m_drawList.begin(); item; item = item->Next() ) + { + if( item->GetFlags() & STRUCT_DELETED ) + continue; + + if( item->Type() != SCH_LABEL_T ) + continue; + + tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() ); + + if( tmp && tmp->GetFlags() & STRUCT_DELETED ) + { + item->SetFlags( STRUCT_DELETED ); + + ITEM_PICKER picker( item, UR_DELETED ); + aList.PushItem( picker ); + } + } + } + + ClearDrawingState(); + + return aList.GetCount(); +} + + +/******************************************************************/ +/* Class SCH_SCREENS to handle the list of screens in a hierarchy */ +/******************************************************************/ + +/** + * Function SortByTimeStamp + * sorts a list of schematic items by time stamp and type. + */ +static bool SortByTimeStamp( const EDA_ITEM* item1, const EDA_ITEM* item2 ) +{ + int ii = item1->GetTimeStamp() - item2->GetTimeStamp(); + + /* If the time stamps are the same, compare type in order to have component objects + * before sheet object. This is done because changing the sheet time stamp + * before the component time stamp could cause the current annotation to be lost. + */ + if( ( ii == 0 && ( item1->Type() != item2->Type() ) ) && ( item1->Type() == SCH_SHEET_T ) ) + ii = -1; + + return ii < 0; +} + + +SCH_SCREENS::SCH_SCREENS() +{ + m_index = 0; + BuildScreenList( g_RootSheet ); +} + + +SCH_SCREENS::~SCH_SCREENS() +{ +} + + +SCH_SCREEN* SCH_SCREENS::GetFirst() +{ + m_index = 0; + + if( m_screens.size() > 0 ) + return m_screens[0]; + + return NULL; +} + + +SCH_SCREEN* SCH_SCREENS::GetNext() +{ + if( m_index < m_screens.size() ) + m_index++; + + return GetScreen( m_index ); +} + + +SCH_SCREEN* SCH_SCREENS::GetScreen( unsigned int aIndex ) const +{ + if( aIndex < m_screens.size() ) + return m_screens[ aIndex ]; + + return NULL; +} + + +void SCH_SCREENS::AddScreenToList( SCH_SCREEN* aScreen ) +{ + if( aScreen == NULL ) + return; + + for( unsigned int i = 0; i < m_screens.size(); i++ ) + { + if( m_screens[i] == aScreen ) + return; + } + + m_screens.push_back( aScreen ); +} + + +void SCH_SCREENS::BuildScreenList( EDA_ITEM* aItem ) +{ + if( aItem && aItem->Type() == SCH_SHEET_T ) + { + SCH_SHEET* ds = (SCH_SHEET*) aItem; + aItem = ds->GetScreen(); + } + + if( aItem && aItem->Type() == SCH_SCREEN_T ) + { + SCH_SCREEN* screen = (SCH_SCREEN*) aItem; + + // Ensure each component has its pointer to its part lib LIB_PART + // up to date (the cost is low if this is the case) + // We do this update here, because most of time this function is called + // to create a netlist, or an ERC, which need this update + screen->CheckComponentsToPartsLinks(); + + AddScreenToList( screen ); + EDA_ITEM* strct = screen->GetDrawItems(); + + while( strct ) + { + if( strct->Type() == SCH_SHEET_T ) + { + BuildScreenList( strct ); + } + + strct = strct->Next(); + } + } +} + + +void SCH_SCREENS::ClearAnnotation() +{ + for( size_t i = 0; i < m_screens.size(); i++ ) + m_screens[i]->ClearAnnotation( NULL ); +} + + +void SCH_SCREENS::SchematicCleanUp() +{ + for( size_t i = 0; i < m_screens.size(); i++ ) + { + // if wire list has changed, delete the undo/redo list to avoid + // pointer problems with deleted data. + if( m_screens[i]->SchematicCleanUp() ) + m_screens[i]->ClearUndoRedoList(); + } +} + + +int SCH_SCREENS::ReplaceDuplicateTimeStamps() +{ + EDA_ITEMS items; + SCH_ITEM* item; + + for( size_t i = 0; i < m_screens.size(); i++ ) + m_screens[i]->GetHierarchicalItems( items ); + + if( items.size() < 2 ) + return 0; + + sort( items.begin(), items.end(), SortByTimeStamp ); + + int count = 0; + + for( size_t ii = 0; ii < items.size() - 1; ii++ ) + { + item = (SCH_ITEM*)items[ii]; + + SCH_ITEM* nextItem = (SCH_ITEM*)items[ii + 1]; + + if( item->GetTimeStamp() == nextItem->GetTimeStamp() ) + { + count++; + + // for a component, update its Time stamp and its paths + // (m_PathsAndReferences field) + if( item->Type() == SCH_COMPONENT_T ) + ( (SCH_COMPONENT*) item )->SetTimeStamp( GetNewTimeStamp() ); + + // for a sheet, update only its time stamp (annotation of its + // components will be lost) + // @todo: see how to change sheet paths for its cmp list (can + // be possible in most cases) + else + item->SetTimeStamp( GetNewTimeStamp() ); + } + } + + return count; +} + + +void SCH_SCREENS::DeleteAllMarkers( enum MARKER_BASE::TYPEMARKER aMarkerType ) +{ + SCH_ITEM* item; + SCH_ITEM* nextItem; + SCH_MARKER* marker; + SCH_SCREEN* screen; + + for( screen = GetFirst(); screen; screen = GetNext() ) + { + for( item = screen->GetDrawItems(); item; item = nextItem ) + { + nextItem = item->Next(); + + if( item->Type() != SCH_MARKER_T ) + continue; + + marker = (SCH_MARKER*) item; + + if( marker->GetMarkerType() != aMarkerType ) + continue; + + screen->DeleteItem( marker ); + } + } +} + + +int SCH_SCREENS::GetMarkerCount( enum MARKER_BASE::TYPEMARKER aMarkerType, + enum MARKER_BASE::MARKER_SEVERITY aSeverity ) +{ + int count = 0; + + for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() ) + { + for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_MARKER_T ) + continue; + + SCH_MARKER* marker = (SCH_MARKER*) item; + + if( ( aMarkerType != MARKER_BASE::MARKER_UNSPEC ) && + ( marker->GetMarkerType() != aMarkerType ) ) + continue; + + if( aSeverity == MARKER_BASE::MARKER_SEVERITY_UNSPEC || + aSeverity == marker->GetErrorLevel() ) + count++; + } + } + + return count; +} + +#if defined(DEBUG) +void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const +{ + // for now, make it look like XML, expand on this later. + NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n"; + + for( EDA_ITEM* item = m_drawList.begin(); item; item = item->Next() ) + { + item->Show( nestLevel+1, os ); + } + + NestedSpace( nestLevel, os ) << "\n"; +} +#endif diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp new file mode 100644 index 00000000..0a03994e --- /dev/null +++ b/eeschema/sch_sheet.cpp @@ -0,0 +1,1236 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_sheet.cpp + * @brief Implementation of SCH_SHEET class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +SCH_SHEET::SCH_SHEET( const wxPoint& pos ) : + SCH_ITEM( NULL, SCH_SHEET_T ) +{ + m_Layer = LAYER_SHEET; + m_pos = pos; + m_size = wxSize( MIN_SHEET_WIDTH, MIN_SHEET_HEIGHT ); + SetTimeStamp( GetNewTimeStamp() ); + m_sheetNameSize = GetDefaultTextSize(); + m_fileNameSize = GetDefaultTextSize(); + m_screen = NULL; + m_name.Printf( wxT( "Sheet%8.8lX" ), (long) m_TimeStamp ); + m_fileName.Printf( wxT( "file%8.8lX.sch" ), (long) m_TimeStamp ); +} + + +SCH_SHEET::SCH_SHEET( const SCH_SHEET& aSheet ) : + SCH_ITEM( aSheet ) +{ + m_pos = aSheet.m_pos; + m_size = aSheet.m_size; + m_Layer = aSheet.m_Layer; + SetTimeStamp( aSheet.m_TimeStamp ); + m_sheetNameSize = aSheet.m_sheetNameSize; + m_fileNameSize = aSheet.m_fileNameSize; + m_screen = aSheet.m_screen; + m_name = aSheet.m_name; + m_fileName = aSheet.m_fileName; + m_pins = aSheet.m_pins; + + for( size_t i = 0; i < m_pins.size(); i++ ) + m_pins[i].SetParent( this ); + + if( m_screen ) + m_screen->IncRefCount(); +} + + +SCH_SHEET::~SCH_SHEET() +{ +// wxLogDebug( wxT( "Destroying sheet " ) + m_name ); + + // also, look at the associated sheet & its reference count + // perhaps it should be deleted also. + if( m_screen ) + { + m_screen->DecRefCount(); + + if( m_screen->GetRefCount() == 0 ) + delete m_screen; + } +} + + +EDA_ITEM* SCH_SHEET::Clone() const +{ + return new SCH_SHEET( *this ); +} + + +void SCH_SHEET::SetScreen( SCH_SCREEN* aScreen ) +{ + if( aScreen == m_screen ) + return; + + if( m_screen != NULL ) + { + m_screen->DecRefCount(); + + if( m_screen->GetRefCount() == 0 ) + { + delete m_screen; + m_screen = NULL; + } + } + + m_screen = aScreen; + + if( m_screen ) + m_screen->IncRefCount(); +} + + +int SCH_SHEET::GetScreenCount() const +{ + if( m_screen == NULL ) + return 0; + + return m_screen->GetRefCount(); +} + + +bool SCH_SHEET::Save( FILE* aFile ) const +{ + if( fprintf( aFile, "$Sheet\n" ) == EOF + || fprintf( aFile, "S %-4d %-4d %-4d %-4d\n", + m_pos.x, m_pos.y, m_size.x, m_size.y ) == EOF ) + return false; + + //save the unique timestamp, like other schematic parts. + if( fprintf( aFile, "U %8.8lX\n", m_TimeStamp ) == EOF ) + return false; + + /* Save schematic sheetname and filename. */ + if( !m_name.IsEmpty() ) + { + if( fprintf( aFile, "F0 %s %d\n", EscapedUTF8( m_name ).c_str(), + m_sheetNameSize ) == EOF ) + return false; + } + + if( !m_fileName.IsEmpty() ) + { + if( fprintf( aFile, "F1 %s %d\n", EscapedUTF8( m_fileName ).c_str(), + m_fileNameSize ) == EOF ) + return false; + } + + /* Save the list of labels in the sheet. */ + + BOOST_FOREACH( const SCH_SHEET_PIN& label, m_pins ) + { + if( !label.Save( aFile ) ) + return false; + } + + if( fprintf( aFile, "$EndSheet\n" ) == EOF ) + return false; + + return true; +} + + +bool SCH_SHEET::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + int fieldNdx, size; + SCH_SHEET_PIN* sheetPin; + char* ptcar; + + SetTimeStamp( GetNewTimeStamp() ); + + // sheets are added to the GetDrawItems() like other schematic components. + // however, in order to preserve the hierarchy (through m_Parent pointers), + // a duplicate of the sheet is added to m_SubSheet array. + // must be a duplicate, references just work for a two-layer structure. + // this is accomplished through the Sync() function. + + if( ((char*)aLine)[0] == '$' ) // line should be "$Sheet" + { + if( !aLine.ReadLine() ) + { + aErrorMsg.Printf( wxT( "Read File Error" ) ); + return false; + } + } + + /* Next line: must be "S xx yy nn mm" with xx, yy = sheet position + * ( upper left corner ) et nn,mm = sheet size */ + if( ( sscanf( &((char*)aLine)[1], "%d %d %d %d", + &m_pos.x, &m_pos.y, &m_size.x, &m_size.y ) != 4 ) + || ( ((char*)aLine)[0] != 'S' ) ) + { + aErrorMsg.Printf( wxT( " ** Eeschema file sheet struct error at line %d, aborted\n" ), + aLine.LineNumber() ); + + aErrorMsg << FROM_UTF8( ((char*)aLine) ); + return false; + } + + /* Read fields */ + for( ; ; ) /* Analysis of lines "Fn" text. */ + { + if( !aLine.ReadLine() ) + return false; + + if( ((char*)aLine)[0] == 'U' ) + { + sscanf( ((char*)aLine) + 1, "%lX", &m_TimeStamp ); + if( m_TimeStamp == 0 ) // zero is not unique! + SetTimeStamp( GetNewTimeStamp() ); + continue; + } + + if( ((char*)aLine)[0] != 'F' ) + break; + + sscanf( ((char*)aLine) + 1, "%d", &fieldNdx ); + + /* Read the field: + * If fieldNdx> = 2: Fn "text" t s posx posy + * If F0 "text" for SheetName + * F1 and "text" for filename + */ + ptcar = ((char*)aLine); + + while( *ptcar && ( *ptcar != '"' ) ) + ptcar++; + + if( *ptcar != '"' ) + { + aErrorMsg.Printf( wxT( "Eeschema file sheet label F%d at line %d, aborted\n" ), + fieldNdx, aLine.LineNumber() ); + aErrorMsg << FROM_UTF8( (char*) aLine ); + return false; + } + + wxString sheetName; + ptcar += ReadDelimitedText( &sheetName, ptcar ); + + if( *ptcar == 0 ) + { + aErrorMsg.Printf( wxT( "Eeschema file sheet field F at line %d, aborted\n" ), + aLine.LineNumber() ); + aErrorMsg << FROM_UTF8( (char*) aLine ); + return false; + } + + if( ( fieldNdx == 0 ) || ( fieldNdx == 1 ) ) + { + if( sscanf( ptcar, "%d", &size ) != 1 ) + { + aErrorMsg.Printf( wxT( "Eeschema file sheet Label error line %d, aborted\n" ), + aLine.LineNumber() ); + + aErrorMsg << FROM_UTF8( (char*) aLine ); + } + + if( size == 0 ) + size = GetDefaultTextSize(); + + if( fieldNdx == 0 ) + { + m_name = sheetName; + m_sheetNameSize = size; + } + else + { + SetFileName( sheetName ); + m_fileNameSize = size; + } + } + + if( fieldNdx > 1 ) + { + sheetPin = new SCH_SHEET_PIN( this ); + + if( !sheetPin->Load( aLine, aErrorMsg ) ) + { + delete sheetPin; + sheetPin = NULL; + return false; + } + + AddPin( sheetPin ); + } + } + + if( strnicmp( "$End", ((char*)aLine), 4 ) != 0 ) + { + aErrorMsg.Printf( wxT( "**Eeschema file end_sheet struct error at line %d, aborted\n" ), + aLine.LineNumber() ); + aErrorMsg << FROM_UTF8( ((char*)aLine) ); + return false; + } + + return true; +} + + +void SCH_SHEET::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem->Type() == SCH_SHEET_T, + wxString::Format( wxT( "SCH_SHEET object cannot swap data with %s object." ), + GetChars( aItem->GetClass() ) ) ); + + SCH_SHEET* sheet = ( SCH_SHEET* ) aItem; + + std::swap( m_pos, sheet->m_pos ); + std::swap( m_size, sheet->m_size ); + std::swap( m_name, sheet->m_name ); + std::swap( m_sheetNameSize, sheet->m_sheetNameSize ); + std::swap( m_fileNameSize, sheet->m_fileNameSize ); + m_pins.swap( sheet->m_pins ); + + // Ensure sheet labels have their .m_Parent member pointing really on their + // parent, after swapping. + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, m_pins ) + { + sheetPin.SetParent( this ); + } + + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, sheet->m_pins ) + { + sheetPin.SetParent( sheet ); + } +} + + +void SCH_SHEET::AddPin( SCH_SHEET_PIN* aSheetPin ) +{ + wxASSERT( aSheetPin != NULL ); + wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T ); + + m_pins.push_back( aSheetPin ); + renumberPins(); +} + + +void SCH_SHEET::RemovePin( SCH_SHEET_PIN* aSheetPin ) +{ + wxASSERT( aSheetPin != NULL ); + wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T ); + + SCH_SHEET_PINS::iterator i; + + for( i = m_pins.begin(); i < m_pins.end(); ++i ) + { + if( *i == aSheetPin ) + { + m_pins.erase( i ); + renumberPins(); + return; + } + } + + wxLogDebug( wxT( "Fix me: attempt to remove label %s which is not in sheet %s." ), + GetChars( aSheetPin->GetShownText() ), GetChars( m_name ) ); +} + + +bool SCH_SHEET::HasPin( const wxString& aName ) +{ + BOOST_FOREACH( SCH_SHEET_PIN pin, m_pins ) + { + if( pin.GetText().CmpNoCase( aName ) == 0 ) + return true; + } + + return false; +} + + +bool SCH_SHEET::IsVerticalOrientation() const +{ + BOOST_FOREACH( SCH_SHEET_PIN pin, m_pins ) + { + if( pin.GetEdge() > 1 ) + return true; + } + return false; +} + + +bool SCH_SHEET::HasUndefinedPins() +{ + BOOST_FOREACH( SCH_SHEET_PIN pin, m_pins ) + { + /* Search the schematic for a hierarchical label corresponding to this sheet label. */ + EDA_ITEM* DrawStruct = m_screen->GetDrawItems(); + const SCH_HIERLABEL* HLabel = NULL; + + for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Next() ) + { + if( DrawStruct->Type() != SCH_HIERARCHICAL_LABEL_T ) + continue; + + HLabel = static_cast( DrawStruct ); + + if( pin.GetText().CmpNoCase( HLabel->GetText() ) == 0 ) + break; // Found! + + HLabel = NULL; + } + + if( HLabel == NULL ) // Corresponding hierarchical label not found. + return true; + } + + return false; +} + + +int SCH_SHEET::GetMinWidth() const +{ + int width = MIN_SHEET_WIDTH; + + for( size_t i = 0; i < m_pins.size(); i++ ) + { + int edge = m_pins[i].GetEdge(); + + // Make sure pin is on right or left side of sheet. + if( edge >= 2 ) + continue; + + EDA_RECT rect = m_pins[i].GetBoundingBox(); + + if( width < rect.GetWidth() ) + width = rect.GetWidth(); + + for( size_t j = 0; j < m_pins.size(); j++ ) + { + if( (i == j) || (m_pins[i].GetPosition().y != m_pins[j].GetPosition().y) ) + continue; + + if( width < rect.GetWidth() + m_pins[j].GetBoundingBox().GetWidth() ) + { + width = rect.GetWidth() + m_pins[j].GetBoundingBox().GetWidth(); + break; + } + } + } + + return width; +} + + +int SCH_SHEET::GetMinHeight() const +{ + int height = MIN_SHEET_HEIGHT; + + for( size_t i = 0; i < m_pins.size(); i++ ) + { + int pinY = m_pins[i].GetPosition().y - m_pos.y; + + if( pinY > height ) + height = pinY; + } + + return height; +} + + +/** + * Delete sheet labels which do not have corresponding hierarchical label. + */ +void SCH_SHEET::CleanupSheet() +{ + SCH_SHEET_PINS::iterator i = m_pins.begin(); + + while( i != m_pins.end() ) + { + /* Search the schematic for a hierarchical label corresponding to this sheet label. */ + EDA_ITEM* DrawStruct = m_screen->GetDrawItems(); + const SCH_HIERLABEL* HLabel = NULL; + + for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Next() ) + { + if( DrawStruct->Type() != SCH_HIERARCHICAL_LABEL_T ) + continue; + + HLabel = static_cast( DrawStruct ); + + if( i->GetText().CmpNoCase( HLabel->GetText() ) == 0 ) + break; // Found! + + HLabel = NULL; + } + + if( HLabel == NULL ) // Hlabel not found: delete sheet label. + m_pins.erase( i ); + else + ++i; + } +} + + +SCH_SHEET_PIN* SCH_SHEET::GetPin( const wxPoint& aPosition ) +{ + BOOST_FOREACH( SCH_SHEET_PIN& pin, m_pins ) + { + if( pin.HitTest( aPosition, 0 ) ) + return &pin; + } + + return NULL; +} + + +int SCH_SHEET::GetPenSize() const +{ + return GetDefaultLineThickness(); +} + + +wxPoint SCH_SHEET::GetSheetNamePosition() +{ + wxPoint pos = m_pos; + + if( IsVerticalOrientation() ) + { + pos.x -= 8; + pos.y += m_size.y; + } + else + { + pos.y -= 8; + } + + return pos; +} + + +wxPoint SCH_SHEET::GetFileNamePosition() +{ + wxPoint pos = m_pos; + int margin = GetPenSize() + 4; + + if( IsVerticalOrientation() ) + { + pos.x += m_size.x + margin; + pos.y += m_size.y; + } + else + { + pos.y += m_size.y + margin; + } + + return pos; +} + + +void SCH_SHEET::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor ) +{ + EDA_COLOR_T txtcolor; + wxString Text; + EDA_COLOR_T color; + int name_orientation; + wxPoint pos_sheetname,pos_filename; + wxPoint pos = m_pos + aOffset; + int lineWidth = GetPenSize(); + EDA_RECT* clipbox = aPanel? aPanel->GetClipBox() : NULL; + + if( aColor >= 0 ) + color = aColor; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( aDC, aDrawMode ); + + GRRect( clipbox, aDC, pos.x, pos.y, + pos.x + m_size.x, pos.y + m_size.y, lineWidth, color ); + + pos_sheetname = GetSheetNamePosition() + aOffset; + pos_filename = GetFileNamePosition() + aOffset; + + if( IsVerticalOrientation() ) + name_orientation = TEXT_ORIENT_VERT; + else + name_orientation = TEXT_ORIENT_HORIZ; + + /* Draw text : SheetName */ + if( aColor > 0 ) + txtcolor = aColor; + else + txtcolor = GetLayerColor( LAYER_SHEETNAME ); + + Text = wxT( "Sheet: " ) + m_name; + DrawGraphicText( clipbox, aDC, pos_sheetname, + txtcolor, Text, name_orientation, + wxSize( m_sheetNameSize, m_sheetNameSize ), + GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM, lineWidth, + false, false ); + + /* Draw text : FileName */ + if( aColor >= 0 ) + txtcolor = aColor; + else + txtcolor = GetLayerColor( LAYER_SHEETFILENAME ); + + Text = wxT( "File: " ) + m_fileName; + DrawGraphicText( clipbox, aDC, pos_filename, + txtcolor, Text, name_orientation, + wxSize( m_fileNameSize, m_fileNameSize ), + GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP, lineWidth, + false, false ); + + + /* Draw text : SheetLabel */ + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, m_pins ) + { + if( !sheetPin.IsMoving() ) + sheetPin.Draw( aPanel, aDC, aOffset, aDrawMode, aColor ); + } +} + + +const EDA_RECT SCH_SHEET::GetBoundingBox() const +{ + wxPoint end; + EDA_RECT box( m_pos, m_size ); + int lineWidth = GetPenSize(); + + // Determine length of texts + wxString text = wxT( "Sheet: " ) + m_name; + int textlen = GraphicTextWidth( text, m_sheetNameSize, false, lineWidth ); + text = wxT( "File: " ) + m_fileName; + int textlen2 = GraphicTextWidth( text, m_fileNameSize, false, lineWidth ); + + // Calculate bounding box X size: + textlen = std::max( textlen, textlen2 ); + end.x = std::max( m_size.x, textlen ); + + // Calculate bounding box pos: + end.y = m_size.y; + end += m_pos; + + // Move upper and lower limits to include texts: + box.SetY( box.GetY() - ( KiROUND( m_sheetNameSize * 1.3 ) + 8 ) ); + end.y += KiROUND( m_fileNameSize * 1.3 ) + 8; + + box.SetEnd( end ); + box.Inflate( lineWidth / 2 ); + + return box; +} + + +int SCH_SHEET::ComponentCount() +{ + int n = 0; + + if( m_screen ) + { + EDA_ITEM* bs; + + for( bs = m_screen->GetDrawItems(); bs != NULL; bs = bs->Next() ) + { + if( bs->Type() == SCH_COMPONENT_T ) + { + SCH_COMPONENT* Cmp = (SCH_COMPONENT*) bs; + + if( Cmp->GetField( VALUE )->GetText().GetChar( 0 ) != '#' ) + n++; + } + + if( bs->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) bs; + n += sheet->ComponentCount(); + } + } + } + + return n; +} + + +bool SCH_SHEET::SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen ) +{ + if( m_screen ) + { + EDA_ITEM* item = m_screen->GetDrawItems(); + + while( item ) + { + if( item->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) item; + + if( sheet->m_screen + && sheet->m_screen->GetFileName().CmpNoCase( aFilename ) == 0 ) + { + *aScreen = sheet->m_screen; + return true; + } + + if( sheet->SearchHierarchy( aFilename, aScreen ) ) + return true; + } + + item = item->Next(); + } + } + + return false; +} + + +bool SCH_SHEET::LocatePathOfScreen( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aList ) +{ + if( m_screen ) + { + aList->Push( this ); + + if( m_screen == aScreen ) + return true; + + EDA_ITEM* strct = m_screen->GetDrawItems(); + + while( strct ) + { + if( strct->Type() == SCH_SHEET_T ) + { + SCH_SHEET* ss = (SCH_SHEET*) strct; + + if( ss->LocatePathOfScreen( aScreen, aList ) ) + return true; + } + + strct = strct->Next(); + } + + aList->Pop(); + } + return false; +} + + +bool SCH_SHEET::Load( SCH_EDIT_FRAME* aFrame ) +{ + bool success = true; + + SCH_SCREEN* screen = NULL; + if( !m_screen ) + { + g_RootSheet->SearchHierarchy( m_fileName, &screen ); + + if( screen ) + { + SetScreen( screen ); + + //do not need to load the sub-sheets - this has already been done. + } + else + { + SetScreen( new SCH_SCREEN( &aFrame->Kiway() ) ); + + success = aFrame->LoadOneEEFile( m_screen, m_fileName ); + + if( success ) + { + EDA_ITEM* bs = m_screen->GetDrawItems(); + + while( bs ) + { + if( bs->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheetstruct = (SCH_SHEET*) bs; + + if( !sheetstruct->Load( aFrame ) ) + success = false; + } + + bs = bs->Next(); + } + } + } + } + + return success; +} + + +int SCH_SHEET::CountSheets() +{ + int count = 1; //1 = this!! + + if( m_screen ) + { + EDA_ITEM* strct = m_screen->GetDrawItems(); + + for( ; strct; strct = strct->Next() ) + { + if( strct->Type() == SCH_SHEET_T ) + { + SCH_SHEET* subsheet = (SCH_SHEET*) strct; + count += subsheet->CountSheets(); + } + } + } + return count; +} + + +wxString SCH_SHEET::GetFileName( void ) const +{ + return m_fileName; +} + + +void SCH_SHEET::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + aList.push_back( MSG_PANEL_ITEM( _( "Sheet Name" ), m_name, CYAN ) ); + aList.push_back( MSG_PANEL_ITEM( _( "File Name" ), m_fileName, BROWN ) ); + +#if 0 // Set to 1 to display the sheet time stamp (mainly for test) + wxString msg; + msg.Printf( wxT( "%.8X" ), m_TimeStamp ); + aList.push_back( MSG_PANEL_ITEM( _( "Time Stamp" ), msg, BLUE ) ); +#endif +} + + +void SCH_SHEET::Rotate(wxPoint aPosition) +{ + RotatePoint( &m_pos, aPosition, 900 ); + RotatePoint( &m_size.x, &m_size.y, 900 ); + + if( m_size.x < 0 ) + { + m_pos.x += m_size.x; + m_size.x = -m_size.x; + } + + if( m_size.y < 0 ) + { + m_pos.y += m_size.y; + m_size.y = -m_size.y; + } + + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, m_pins ) + { + sheetPin.Rotate( aPosition ); + } +} + + +void SCH_SHEET::MirrorX( int aXaxis_position ) +{ + MIRROR( m_pos.y, aXaxis_position ); + m_pos.y -= m_size.y; + + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, m_pins ) + { + sheetPin.MirrorX( aXaxis_position ); + } +} + + +void SCH_SHEET::MirrorY( int aYaxis_position ) +{ + MIRROR( m_pos.x, aYaxis_position ); + m_pos.x -= m_size.x; + + BOOST_FOREACH( SCH_SHEET_PIN& label, m_pins ) + { + label.MirrorY( aYaxis_position ); + } +} + +void SCH_SHEET::SetPosition( const wxPoint& aPosition ) +{ + // Remember the sheet and all pin sheet positions must be + // modified. So use Move function to do that. + Move( aPosition - m_pos ); +} + + + +void SCH_SHEET::Resize( const wxSize& aSize ) +{ + if( aSize == m_size ) + return; + + m_size = aSize; + + /* Move the sheet labels according to the new sheet size. */ + BOOST_FOREACH( SCH_SHEET_PIN& label, m_pins ) + { + label.ConstrainOnEdge( label.GetPosition() ); + } +} + + +bool SCH_SHEET::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ) +{ + wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText() ); + + // Ignore the sheet file name if searching to replace. + if( !(aSearchData.GetFlags() & FR_SEARCH_REPLACE) + && SCH_ITEM::Matches( m_fileName, aSearchData ) ) + { + if( aFindLocation ) + *aFindLocation = GetFileNamePosition(); + + return true; + } + + if( SCH_ITEM::Matches( m_name, aSearchData ) ) + { + if( aFindLocation ) + *aFindLocation = GetSheetNamePosition(); + + return true; + } + + return false; +} + + +bool SCH_SHEET::Replace( wxFindReplaceData& aSearchData, void* aAuxData ) +{ + return EDA_ITEM::Replace( aSearchData, m_name ); +} + + +void SCH_SHEET::renumberPins() +{ + int id = 2; + + BOOST_FOREACH( SCH_SHEET_PIN& pin, m_pins ) + { + pin.SetNumber( id ); + id++; + } +} + + +void SCH_SHEET::GetEndPoints( std::vector & aItemList ) +{ + for( unsigned ii = 0; ii < GetPins().size(); ii++ ) + { + SCH_SHEET_PIN &pinsheet = GetPins()[ii]; + + wxCHECK2_MSG( pinsheet.Type() == SCH_SHEET_PIN_T, continue, + wxT( "Invalid item in schematic sheet pin list. Bad programmer!" ) ); + + pinsheet.GetEndPoints( aItemList ); + } +} + + +bool SCH_SHEET::IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ) +{ + bool currentState = IsDangling(); + + BOOST_FOREACH( SCH_SHEET_PIN& pinsheet, GetPins() ) + { + pinsheet.IsDanglingStateChanged( aItemList ); + } + + return currentState != IsDangling(); +} + + +bool SCH_SHEET::IsDangling() const +{ + // If any hierarchical label in the sheet is dangling, then the sheet is dangling. + for( size_t i = 0; i < GetPins().size(); i++ ) + { + if( GetPins()[i].IsDangling() ) + return true; + } + + return false; +} + + +bool SCH_SHEET::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + EDA_RECT boundingBox = GetBoundingBox(); + + if( aRect.Intersects( boundingBox ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_SHEET::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + for( size_t i = 0; i < GetPins().size(); i++ ) + aPoints.push_back( GetPins()[i].GetPosition() ); +} + + +SEARCH_RESULT SCH_SHEET::Visit( INSPECTOR* aInspector, const void* aTestData, + const KICAD_T aFilterTypes[] ) +{ + KICAD_T stype; + + for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p ) + { + // If caller wants to inspect my type + if( stype == Type() ) + { + if( SEARCH_QUIT == aInspector->Inspect( this, NULL ) ) + return SEARCH_QUIT; + } + else if( stype == SCH_SHEET_PIN_T ) + { + // Test the sheet labels. + for( size_t i = 0; i < m_pins.size(); i++ ) + { + if( SEARCH_QUIT == aInspector->Inspect( &m_pins[ i ], (void*) this ) ) + return SEARCH_QUIT; + } + } + } + + return SEARCH_CONTINUE; +} + + +wxString SCH_SHEET::GetSelectMenuText() const +{ + wxString tmp; + tmp.Printf( _( "Hierarchical Sheet %s" ), GetChars( m_name ) ); + return tmp; +} + + +bool SCH_SHEET::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool SCH_SHEET::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +wxPoint SCH_SHEET::GetResizePosition() const +{ + return wxPoint( m_pos.x + m_size.GetWidth(), m_pos.y + m_size.GetHeight() ); +} + + +void SCH_SHEET::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + SCH_SHEET_PATH sheetPath = *aSheetPath; + sheetPath.Push( this ); + + for( size_t i = 0; i < m_pins.size(); i++ ) + { + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + item->m_SheetPathInclude = sheetPath; + item->m_SheetPath = *aSheetPath; + item->m_Comp = &m_pins[i]; + item->m_Link = this; + item->m_Type = NET_SHEETLABEL; + item->m_ElectricalType = m_pins[i].GetShape(); + item->m_Label = m_pins[i].GetText(); + item->m_Start = item->m_End = m_pins[i].GetPosition(); + aNetListItems.push_back( item ); + + if( IsBusLabel( m_pins[i].GetText() ) ) + item->ConvertBusToNetListItems( aNetListItems ); + } +} + + +void SCH_SHEET::Plot( PLOTTER* aPlotter ) +{ + EDA_COLOR_T txtcolor = UNSPECIFIED_COLOR; + wxSize size; + wxString Text; + int name_orientation; + wxPoint pos_sheetname, pos_filename; + wxPoint pos; + + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + + int thickness = GetPenSize(); + aPlotter->SetCurrentLineWidth( thickness ); + + aPlotter->MoveTo( m_pos ); + pos = m_pos; + pos.x += m_size.x; + + aPlotter->LineTo( pos ); + pos.y += m_size.y; + + aPlotter->LineTo( pos ); + pos = m_pos; + pos.y += m_size.y; + + aPlotter->LineTo( pos ); + aPlotter->FinishTo( m_pos ); + + if( IsVerticalOrientation() ) + { + pos_sheetname = wxPoint( m_pos.x - 8, m_pos.y + m_size.y ); + pos_filename = wxPoint( m_pos.x + m_size.x + 4, m_pos.y + m_size.y ); + name_orientation = TEXT_ORIENT_VERT; + } + else + { + pos_sheetname = wxPoint( m_pos.x, m_pos.y - 4 ); + pos_filename = wxPoint( m_pos.x, m_pos.y + m_size.y + 4 ); + name_orientation = TEXT_ORIENT_HORIZ; + } + + /* Draw texts: SheetName */ + Text = m_name; + size = wxSize( m_sheetNameSize, m_sheetNameSize ); + + //pos = m_pos; pos.y -= 4; + thickness = GetDefaultLineThickness(); + thickness = Clamp_Text_PenSize( thickness, size, false ); + + aPlotter->SetColor( GetLayerColor( LAYER_SHEETNAME ) ); + + bool italic = false; + aPlotter->Text( pos_sheetname, txtcolor, Text, name_orientation, size, + GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM, + thickness, italic, false ); + + /*Draw texts : FileName */ + Text = GetFileName(); + size = wxSize( m_fileNameSize, m_fileNameSize ); + thickness = GetDefaultLineThickness(); + thickness = Clamp_Text_PenSize( thickness, size, false ); + + aPlotter->SetColor( GetLayerColor( LAYER_SHEETFILENAME ) ); + + aPlotter->Text( pos_filename, txtcolor, Text, name_orientation, size, + GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP, + thickness, italic, false ); + + aPlotter->SetColor( GetLayerColor( GetLayer() ) ); + + /* Draw texts : SheetLabel */ + for( size_t i = 0; i < m_pins.size(); i++ ) + { + m_pins[i].Plot( aPlotter ); + } +} + + +SCH_ITEM& SCH_SHEET::operator=( const SCH_ITEM& aItem ) +{ + wxLogDebug( wxT( "Sheet assignment operator." ) ); + + wxCHECK_MSG( Type() == aItem.Type(), *this, + wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) + + GetClass() ); + + if( &aItem != this ) + { + SCH_ITEM::operator=( aItem ); + + SCH_SHEET* sheet = (SCH_SHEET*) &aItem; + + m_pos = sheet->m_pos; + m_size = sheet->m_size; + m_name = sheet->m_name; + m_sheetNameSize = sheet->m_sheetNameSize; + m_fileNameSize = sheet->m_fileNameSize; + m_pins = sheet->m_pins; + + // Ensure sheet labels have their #m_Parent member pointing really on their + // parent, after assigning. + BOOST_FOREACH( SCH_SHEET_PIN& sheetPin, m_pins ) + { + sheetPin.SetParent( this ); + } + } + + return *this; +} + + +#if defined(DEBUG) + +void SCH_SHEET::Show( int nestLevel, std::ostream& os ) const +{ + // XML output: + wxString s = GetClass(); + + NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << ">" << " sheet_name=\"" + << TO_UTF8( m_name ) << '"' << ">\n"; + + // show all the pins, and check the linked list integrity + BOOST_FOREACH( const SCH_SHEET_PIN& label, m_pins ) + { + label.Show( nestLevel + 1, os ); + } + + NestedSpace( nestLevel, os ) << "\n" << std::flush; +} + +#endif diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h new file mode 100644 index 00000000..3304a0d7 --- /dev/null +++ b/eeschema/sch_sheet.h @@ -0,0 +1,600 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_sheet.h + * @brief Definition of the SCH_SHEET class for Eeschema. + */ + +#ifndef SCH_SHEEET_H +#define SCH_SHEEET_H + +#include +#include +#include + + +class LINE_READER; +class SCH_SCREEN; +class SCH_SHEET; +class SCH_SHEET_PIN; +class SCH_SHEET_PATH; +class DANGLING_END_ITEM; +class SCH_EDIT_FRAME; +class NETLIST_OBJECT_LIST; + + +#define MIN_SHEET_WIDTH 500 +#define MIN_SHEET_HEIGHT 150 + + +/** + * Class SCH_SHEET_PIN + * defines a sheet pin (label) used in sheets to create hierarchical schematics. + * + * A SCH_SHEET_PIN is used to create a hierarchical sheet in the same way a + * pin is used in a component. It connects the objects in the sheet object + * to the objects in the schematic page to the objects in the page that is + * represented by the sheet. In a sheet object, a SCH_SHEET_PIN must be + * connected to a wire, bus, or label. In the schematic page represented by + * the sheet, it corresponds to a hierarchical label. + */ +class SCH_SHEET_PIN : public SCH_HIERLABEL +{ +private: + int m_number; ///< Label number use for saving sheet label to file. + ///< Sheet label numbering begins at 2. + ///< 0 is reserved for the sheet name. + ///< 1 is reserve for the sheet file name. + + /** + * Defines the edge of the sheet that the sheet pin is positioned + * SHEET_LEFT_SIDE = 0: pin on left side + * SHEET_RIGHT_SIDE = 1: pin on right side + * SHEET_TOP_SIDE = 2: pin on top side + * SHEET_BOTTOM_SIDE =3: pin on bottom side + * + * For compatibility reasons, this does not follow same values as text orientation. + */ + enum SHEET_SIDE + { + SHEET_LEFT_SIDE = 0, + SHEET_RIGHT_SIDE, + SHEET_TOP_SIDE, + SHEET_BOTTOM_SIDE, + SHEET_UNDEFINED_SIDE + }; + SHEET_SIDE m_edge; + +public: + SCH_SHEET_PIN( SCH_SHEET* parent, + const wxPoint& pos = wxPoint( 0, 0 ), + const wxString& text = wxEmptyString ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_SHEET_PIN() { } + + wxString GetClass() const + { + return wxT( "SCH_SHEET_PIN" ); + } + + bool operator ==( const SCH_SHEET_PIN* aPin ) const; + + /** + * Virtual function IsMovableFromAnchorPoint + * Return true for items which are moved with the anchor point at mouse cursor + * and false for items moved with no reference to anchor (usually large items) + * @return true for a hierarchical sheet pin + */ + bool IsMovableFromAnchorPoint() { return true; } + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + /** + * Function CreateGraphicShape (virtual) + * Calculates the graphic shape (a polygon) associated to the text + * @param aPoints = a buffer to fill with polygon corners coordinates + * @param aPos = Position of the shape + */ + void CreateGraphicShape( std::vector & aPoints, const wxPoint& aPos ); + + void SwapData( SCH_ITEM* aItem ); + + int GetPenSize() const; + + /** + * Get the sheet label number. + * + * @return Number of the sheet label. + */ + int GetNumber() const { return m_number; } + + /** + * Set the sheet label number. + * + * @param aNumber - New sheet number label. + */ + void SetNumber( int aNumber ); + + void SetEdge( SHEET_SIDE aEdge ); + + SHEET_SIDE GetEdge() const; + + /** + * Function ConstrainOnEdge + * is used to adjust label position to edge based on proximity to vertical / horizontal edge + * of the parent sheet. + */ + void ConstrainOnEdge( wxPoint Pos ); + + /** + * Get the parent sheet object of this sheet pin. + * + * @return The sheet that is the parent of this sheet pin or NULL if it does + * not have a parent. + */ + SCH_SHEET* GetParent() const { return (SCH_SHEET*) m_Parent; } + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + m_Pos += aMoveVector; + } + + void MirrorY( int aYaxis_position ); + + void Rotate( wxPoint aPosition ); + + void MirrorX( int aXaxis_position ); + + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + bool Replace( wxFindReplaceData& aSearchData, void* aAuxData = NULL ) + { + return EDA_ITEM::Replace( aSearchData, m_Text ); + } + + bool IsReplaceable() const { return true; } + + void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ); + + bool IsConnectable() const { return true; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_hierar_pin_xpm; } + + void SetPosition( const wxPoint& aPosition ) { ConstrainOnEdge( aPosition ); } + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + EDA_ITEM* Clone() const; +}; + + +typedef boost::ptr_vector SCH_SHEET_PINS; + + +/** + * Class SCH_SHEET + * is the sheet symbol placed in a schematic, and is the entry point for a sub schematic. + */ +class SCH_SHEET : public SCH_ITEM +{ + friend class SCH_SHEET_PIN; + + /// Screen that contains the physical data for the sheet. In complex hierarchies + /// multiple sheets can share a common screen. + SCH_SCREEN* m_screen; + + /// The list of sheet connection points. + SCH_SHEET_PINS m_pins; + + /// The file name is also in the #SCH_SCREEN object associated with the sheet. It is + /// also needed here for loading after reading the sheet description from file. + wxString m_fileName; + + /// This is equivalent to the reference designator for components and is stored in F0 + /// sheet pin in the schematic file. + wxString m_name; + + /// The height of the text used to draw the sheet name. + int m_sheetNameSize; + + /// The height of the text used to draw the file name. + int m_fileNameSize; + + /// The position of the sheet. + wxPoint m_pos; + + /// The size of the sheet. + wxSize m_size; + +public: + SCH_SHEET( const wxPoint& pos = wxPoint( 0, 0 ) ); + + /** + * Copy Constructor + * clones \a aSheet into a new object. All sheet pins are copied as is except and + * the SCH_SHEET_PIN's #m_Parent pointers are set to the new copied parent object. + */ + SCH_SHEET( const SCH_SHEET& aSheet ); + + ~SCH_SHEET(); + + wxString GetClass() const + { + return wxT( "SCH_SHEET" ); + } + + /** + * Virtual function IsMovableFromAnchorPoint + * Return true for items which are moved with the anchor point at mouse cursor + * and false for items moved with no reference to anchor + * Usually return true for small items (labels, junctions) and false for + * items which can be large (hierarchical sheets, compoments) + * @return false for a hierarchical sheet + */ + bool IsMovableFromAnchorPoint() { return false; } + + wxString GetName() const { return m_name; } + + void SetName( const wxString& aName ) { m_name = aName; } + + int GetSheetNameSize() const { return m_sheetNameSize; } + + void SetSheetNameSize( int aSize ) { m_sheetNameSize = aSize; } + + int GetFileNameSize() const { return m_fileNameSize; } + + void SetFileNameSize( int aSize ) { m_fileNameSize = aSize; } + + SCH_SCREEN* GetScreen() { return m_screen; } + + wxSize GetSize() { return m_size; } + + void SetSize( const wxSize& aSize ) { m_size = aSize; } + + /** + * Function SetScreen + * sets the screen associated with this sheet to \a aScreen. + *

      + * The screen reference counting is performed by SetScreen. If \a aScreen is not + * the same as the current screen, the current screen reference count is decremented + * and \a aScreen becomes the screen for the sheet. If the current screen reference + * count reaches zero, the current screen is deleted. NULL is a valid value for + * \a aScreen. + *

      + * @param aScreen The new screen to associate with the sheet. + */ + void SetScreen( SCH_SCREEN* aScreen ); + + /** + * Function GetScreenCount + * returns the number of times the associated screen for the sheet is being used. If + * no screen is associated with the sheet, then zero is returned. + */ + int GetScreenCount() const; + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + /* there is no member for orientation in sch_sheet, to preserve file + * format, we detect orientation based on pin edges + */ + bool IsVerticalOrientation() const; + + /** + * Add aSheetPin to the sheet. + * + * Note: Once a sheet pin is added to the sheet, it is owned by the sheet. + * Do not delete the sheet pin object or you will likely get a segfault + * when the sheet is destroyed. + * + * @param aSheetPin The sheet pin item to add to the sheet. + */ + void AddPin( SCH_SHEET_PIN* aSheetPin ); + + SCH_SHEET_PINS& GetPins() { return m_pins; } + + SCH_SHEET_PINS& GetPins() const + { + return const_cast< SCH_SHEET_PINS& >( m_pins ); + } + + /** + * Remove \a aSheetPin from the sheet. + * + * @param aSheetPin The sheet pin item to remove from the sheet. + */ + void RemovePin( SCH_SHEET_PIN* aSheetPin ); + + /** + * Delete sheet label which do not have a corresponding hierarchical label. + * + * Note: Make sure you save a copy of the sheet in the undo list before calling + * CleanupSheet() otherwise any unreferenced sheet labels will be lost. + */ + void CleanupSheet(); + + /** + * Return the sheet pin item found at \a aPosition in the sheet. + * + * @param aPosition The position to check for a sheet pin. + * + * @return The sheet pin found at \a aPosition or NULL if no sheet pin is found. + */ + SCH_SHEET_PIN* GetPin( const wxPoint& aPosition ); + + /** + * Checks if the sheet already has a sheet pin named \a aName. + * + * @param aName Name of the sheet pin to search for. + * + * @return True if sheet pin with \a aName is found, otherwise false. + */ + bool HasPin( const wxString& aName ); + + bool HasPins() { return !m_pins.empty(); } + + /** + * Check all sheet labels against schematic for undefined hierarchical labels. + * + * @return True if there are any undefined labels. + */ + bool HasUndefinedPins(); + + /** + * Function GetMinWidth + * returns the minimum width of the sheet based on the widths of the sheet pin text. + * + *

      + * The minimum sheet width is determined by the width of the bounding box of each + * hierarchical sheet pin. If two pins are horizontally adjacent ( same Y position ) + * to each other, the sum of the bounding box widths is used. If at some point in + * the future sheet objects can be rotated or pins can be placed in the vertical + * orientation, this function will need to be changed. + *

      + * + * @return The minimum width the sheet can be resized. + */ + int GetMinWidth() const; + + /** + * Function GetMinHeight + * returns the minimum height that the sheet can be resized based on the sheet pin + * positions. + * + *

      + * The minimum width of a sheet is determined by the Y axis location of the bottom + * most sheet pin. If at some point in the future sheet objects can be rotated or + * pins can be placed in the vertical orientation, this function will need to be + * changed. + *

      + * + * @return The minimum height the sheet can be resized. + */ + int GetMinHeight() const; + + int GetPenSize() const; + + void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + GR_DRAWMODE aDrawMode, EDA_COLOR_T aColor = UNSPECIFIED_COLOR ); + + EDA_RECT const GetBoundingBox() const; + + /** + * Function GetResizePos + * returns the position of the lower right corner of the sheet in drawing units. + * + * @return A wxPoint containing lower right corner of the sheet in drawing units. + */ + wxPoint GetResizePosition() const; + + void SwapData( SCH_ITEM* aItem ); + + /** + * Function ComponentCount + * count our own components, without the power components. + * @return the component count. + */ + int ComponentCount(); + + /** + * Function Load. + * for the sheet: load the file m_fileName + * if a screen already exists, the file is already read. + * m_screen point on the screen, and its m_RefCount is + * incremented + * else creates a new associated screen and load the data file. + * @param aFrame = a SCH_EDIT_FRAME pointer to the maim schematic frame + * @return true if OK + */ + bool Load( SCH_EDIT_FRAME* aFrame ); + + /** + * Function SearchHierarchy + * search the existing hierarchy for an instance of screen "FileName". + * @param aFilename = the filename to find + * @param aScreen = a location to return a pointer to the screen (if found) + * @return bool if found, and a pointer to the screen + */ + bool SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen ); + + /** + * Function LocatePathOfScreen + * search the existing hierarchy for an instance of screen "FileName". + * don't bother looking at the root sheet - it must be unique, + * no other references to its m_screen otherwise there would be + * loops in the hierarchy. + * + * @param aScreen = the SCH_SCREEN* screen that we search for + * @param aList = the SCH_SHEET_PATH* that must be used + * @return true if found + */ + bool LocatePathOfScreen( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aList ); + + /** + * Function CountSheets + * calculates the number of sheets found in "this" + * this number includes the full subsheets count + * @return the full count of sheets+subsheets contained by "this" + */ + int CountSheets(); + + /** + * Function GetFileName + * return the filename corresponding to this sheet + * @return a wxString containing the filename + */ + wxString GetFileName( void ) const; + + // Set a new filename without changing anything else + void SetFileName( const wxString& aFilename ) + { + m_fileName = aFilename; + // Filenames are stored using unix notation + m_fileName.Replace( wxT("\\"), wxT("/") ); + } + + bool ChangeFileName( SCH_EDIT_FRAME* aFrame, const wxString& aFileName ); + + //void RemoveSheet(SCH_SHEET* sheet); + //to remove a sheet, just delete it + //-- the destructor should take care of everything else. + + // Geometric transforms (used in block operations): + + void Move( const wxPoint& aMoveVector ) + { + m_pos += aMoveVector; + + BOOST_FOREACH( SCH_SHEET_PIN& pin, m_pins ) + { + pin.Move( aMoveVector ); + } + } + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + bool Replace( wxFindReplaceData& aSearchData, void* aAuxData = NULL ); + + bool IsReplaceable() const { return true; } + + /** + * Resize this sheet to aSize and adjust all of the labels accordingly. + * + * @param aSize - The new size for this sheet. + */ + void Resize( const wxSize& aSize ); + + /** + * Function GetSheetNamePosition + * @return the position of the anchor of sheet name text + */ + wxPoint GetSheetNamePosition(); + + /** + * Function GetFileNamePosition + * @return the position of the anchor of filename text + */ + wxPoint GetFileNamePosition(); + + void GetEndPoints( std::vector & aItemList ); + + bool IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ); + + bool IsDangling() const; + + bool IsSelectStateChanged( const wxRect& aRect ); + + bool IsConnectable() const { return true; } + + void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const; + + SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData, + const KICAD_T scanTypes[] ); + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_hierarchical_subsheet_xpm; } + + void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ); + + SCH_ITEM& operator=( const SCH_ITEM& aSheet ); + + wxPoint GetPosition() const { return m_pos; } + + void SetPosition( const wxPoint& aPosition ); + + bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const; + + void Plot( PLOTTER* aPlotter ); + + EDA_ITEM* Clone() const; + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif + +protected: + + /** + * Renumber the sheet pins in the sheet. + * + * This method is used internally by SCH_SHEET to update the pin numbering + * when the pin list changes. Make sure you call this method any time a + * sheet pin is added or removed. + */ + void renumberPins(); +}; + + +typedef std::vector< SCH_SHEET* > SCH_SHEETS; + +#endif /* SCH_SHEEET_H */ diff --git a/eeschema/sch_sheet_path.cpp b/eeschema/sch_sheet_path.cpp new file mode 100644 index 00000000..790a22cb --- /dev/null +++ b/eeschema/sch_sheet_path.cpp @@ -0,0 +1,924 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_sheet_path.cpp + * @brief SCH_SHEET_PATH class implementation. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +SCH_SHEET_PATH::SCH_SHEET_PATH() +{ + for( int i = 0; iType() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) schitem; + Push( sheet ); + + if( aPath == Path() ) + return true; + + if( BuildSheetPathInfoFromSheetPathValue( aPath ) ) + return true; + + Pop(); + } + + schitem = schitem->Next(); + } + + return false; +} + + +int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const +{ + if( m_numSheets > aSheetPathToTest.m_numSheets ) + return 1; + + if( m_numSheets < aSheetPathToTest.m_numSheets ) + return -1; + + //otherwise, same number of sheets. + for( unsigned i = 0; iGetTimeStamp() > aSheetPathToTest.m_sheets[i]->GetTimeStamp() ) + return 1; + + if( m_sheets[i]->GetTimeStamp() < aSheetPathToTest.m_sheets[i]->GetTimeStamp() ) + return -1; + } + + return 0; +} + + +SCH_SHEET* SCH_SHEET_PATH::Last() const +{ + if( m_numSheets ) + return m_sheets[m_numSheets - 1]; + + return NULL; +} + + +SCH_SCREEN* SCH_SHEET_PATH::LastScreen() const +{ + SCH_SHEET* lastSheet = Last(); + + if( lastSheet ) + return lastSheet->GetScreen(); + + return NULL; +} + + +SCH_ITEM* SCH_SHEET_PATH::LastDrawList() const +{ + SCH_SHEET* lastSheet = Last(); + + if( lastSheet && lastSheet->GetScreen() ) + return lastSheet->GetScreen()->GetDrawItems(); + + return NULL; +} + + +SCH_ITEM* SCH_SHEET_PATH::FirstDrawList() const +{ + SCH_ITEM* item = NULL; + + if( m_numSheets && m_sheets[0]->GetScreen() ) + item = m_sheets[0]->GetScreen()->GetDrawItems(); + + /* @fixme - These lists really should be one of the boost pointer containers. This + * is a brain dead hack to allow reverse iteration of EDA_ITEM linked + * list. + */ + SCH_ITEM* lastItem = NULL; + + while( item ) + { + lastItem = item; + item = item->Next(); + } + + return lastItem; +} + + +void SCH_SHEET_PATH::Push( SCH_SHEET* aSheet ) +{ + wxCHECK_RET( m_numSheets < DSLSZ, + wxString::Format( _( "Schematic sheets can only be nested %d levels deep." ), + DSLSZ ) ); + + m_sheets[ m_numSheets ] = aSheet; + m_numSheets++; +} + + +SCH_SHEET* SCH_SHEET_PATH::Pop() +{ + if( m_numSheets > 0 ) + { + m_numSheets--; + return m_sheets[m_numSheets]; + } + + return NULL; +} + + +wxString SCH_SHEET_PATH::Path() const +{ + wxString s, t; + + s = wxT( "/" ); // This is the root path + + // start at 1 to avoid the root sheet, + // which does not need to be added to the path + // it's timestamp changes anyway. + for( unsigned i = 1; i < m_numSheets; i++ ) + { + t.Printf( _( "%8.8lX/" ), (long unsigned) m_sheets[i]->GetTimeStamp() ); + s = s + t; + } + + return s; +} + + +wxString SCH_SHEET_PATH::PathHumanReadable() const +{ + wxString s; + + s = wxT( "/" ); + + // start at 1 to avoid the root sheet, as above. + for( unsigned i = 1; i< m_numSheets; i++ ) + { + s = s + m_sheets[i]->GetName() + wxT( "/" ); + } + + return s; +} + + +void SCH_SHEET_PATH::UpdateAllScreenReferences() +{ + EDA_ITEM* t = LastDrawList(); + + while( t ) + { + if( t->Type() == SCH_COMPONENT_T ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) t; + component->GetField( REFERENCE )->SetText( component->GetRef( this ) ); + component->UpdateUnit( component->GetUnitSelection( this ) ); + } + + t = t->Next(); + } +} + + +void SCH_SHEET_PATH::AnnotatePowerSymbols( PART_LIBS* aLibs, int* aReference ) +{ + int ref = 1; + + if( aReference ) + ref = *aReference; + + for( EDA_ITEM* item = LastDrawList(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + LIB_PART* part = aLibs->FindLibPart( component->GetPartName() ); + + if( !part || !part->IsPower() ) + continue; + + wxString refstr = component->GetPrefix(); + + //str will be "C?" or so after the ClearAnnotation call. + while( refstr.Last() == '?' ) + refstr.RemoveLast(); + + if( !refstr.StartsWith( wxT( "#" ) ) ) + refstr = wxT( "#" ) + refstr; + + refstr << wxT( "0" ) << ref; + component->SetRef( this, refstr ); + ref++; + } + + if( aReference ) + *aReference = ref; +} + + +void SCH_SHEET_PATH::GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols ) +{ + // Search to sheet path number: + int sheetnumber = 1; // 1 = root + + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext(), sheetnumber++ ) + { + if( Cmp( *path ) == 0 ) + break; + } + + for( SCH_ITEM* item = LastDrawList(); item; item = item->Next() ) + { + if( item->Type() == SCH_COMPONENT_T ) + { + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + // Skip pseudo components, which have a reference starting with #. This mainly + // affects power symbols. + if( !aIncludePowerSymbols && component->GetRef( this )[0] == wxT( '#' ) ) + continue; + + LIB_PART* part = aLibs->FindLibPart( component->GetPartName() ); + if( part ) + { + SCH_REFERENCE reference = SCH_REFERENCE( component, part, *this ); + reference.SetSheetNumber( sheetnumber ); + aReferences.AddItem( reference ); + } + } + } +} + +void SCH_SHEET_PATH::GetMultiUnitComponents( PART_LIBS* aLibs, SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, + bool aIncludePowerSymbols ) +{ + // Find sheet path number + int sheetnumber = 1; // 1 = root + + SCH_SHEET_LIST sheetList; + + for( SCH_SHEET_PATH* path = sheetList.GetFirst(); path; path = sheetList.GetNext(), sheetnumber++ ) + { + if( Cmp( *path ) == 0 ) + break; + } + + for( SCH_ITEM* item = LastDrawList(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) continue; + SCH_COMPONENT* component = (SCH_COMPONENT*) item; + + // Skip pseudo components, which have a reference starting with #. This mainly + // affects power symbols. + if( !aIncludePowerSymbols && component->GetRef( this )[0] == wxT( '#' ) ) + continue; + + LIB_PART* part = aLibs->FindLibPart( component->GetPartName() ); + if( part && part->GetUnitCount() > 1 ) + { + SCH_REFERENCE reference = SCH_REFERENCE( component, part, *this ); + reference.SetSheetNumber( sheetnumber ); + wxString reference_str = reference.GetRef(); + + // Never lock unassigned references + if( reference_str[reference_str.Len() - 1] == '?' ) continue; + + aRefList[reference_str].AddItem( reference ); + } + } +} + + +SCH_ITEM* SCH_SHEET_PATH::FindNextItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap ) const +{ + bool hasWrapped = false; + bool firstItemFound = false; + SCH_ITEM* drawItem = LastDrawList(); + + while( drawItem ) + { + if( drawItem->Type() == aType ) + { + if( !aLastItem || firstItemFound ) + { + return drawItem; + } + else if( !firstItemFound && drawItem == aLastItem ) + { + firstItemFound = true; + } + } + + drawItem = drawItem->Next(); + + if( !drawItem && aLastItem && aWrap && !hasWrapped ) + { + hasWrapped = true; + drawItem = LastDrawList(); + } + } + + return NULL; +} + + +SCH_ITEM* SCH_SHEET_PATH::FindPreviousItem( KICAD_T aType, SCH_ITEM* aLastItem, bool aWrap ) const +{ + bool hasWrapped = false; + bool firstItemFound = false; + SCH_ITEM* drawItem = FirstDrawList(); + + while( drawItem ) + { + if( drawItem->Type() == aType ) + { + if( aLastItem == NULL || firstItemFound ) + { + return drawItem; + } + else if( !firstItemFound && drawItem == aLastItem ) + { + firstItemFound = true; + } + } + + drawItem = drawItem->Back(); + + if( drawItem == NULL && aLastItem && aWrap && !hasWrapped ) + { + hasWrapped = true; + drawItem = FirstDrawList(); + } + } + + return NULL; +} + + +bool SCH_SHEET_PATH::SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint, + bool aSetVisible ) +{ + SCH_SCREEN* screen = LastScreen(); + + if( screen == NULL ) + return false; + + return screen->SetComponentFootprint( this, aReference, aFootPrint, aSetVisible ); +} + + +SCH_SHEET_PATH& SCH_SHEET_PATH::operator=( const SCH_SHEET_PATH& d1 ) +{ + if( this == &d1 ) // Self assignment is bad! + return *this; + + m_numSheets = d1.m_numSheets; + + unsigned i; + + for( i = 0; i < m_numSheets; i++ ) + m_sheets[i] = d1.m_sheets[i]; + + for( ; i < DSLSZ; i++ ) + m_sheets[i] = 0; + + return *this; +} + + +bool SCH_SHEET_PATH::operator==( const SCH_SHEET_PATH& d1 ) const +{ + if( m_numSheets != d1.m_numSheets ) + return false; + + for( unsigned i = 0; i < m_numSheets; i++ ) + { + if( m_sheets[i] != d1.m_sheets[i] ) + return false; + } + + return true; +} + + +bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, + const wxString& aDestFileName ) const +{ + wxFileName rootFn = g_RootSheet->GetFileName(); + wxFileName srcFn = aSrcFileName; + wxFileName destFn = aDestFileName; + + if( srcFn.IsRelative() ) + srcFn.MakeAbsolute( rootFn.GetPath() ); + + if( destFn.IsRelative() ) + destFn.MakeAbsolute( rootFn.GetPath() ); + + + // The source and destination sheet file names cannot be the same. + if( srcFn == destFn ) + return true; + + /// @todo Store sheet file names with full path, either relative to project path + /// or absolute path. The current design always assumes subsheet files are + /// located in the project folder which may or may not be desirable. + unsigned i = 0; + + while( i < m_numSheets ) + { + wxFileName cmpFn = m_sheets[i]->GetFileName(); + + if( cmpFn.IsRelative() ) + cmpFn.MakeAbsolute( rootFn.GetPath() ); + + // Test if the file name of the destination sheet is in anywhere in this sheet path. + if( cmpFn == destFn ) + break; + + i++; + } + + // The destination sheet file name was not found in the sheet path or the destination + // sheet file name is the root sheet so no recursion is possible. + if( i >= m_numSheets || i == 0 ) + return false; + + // Walk back up to the root sheet to see if the source file name is already a parent in + // the sheet path. If so, recursion will occur. + do + { + i -= 1; + + wxFileName cmpFn = m_sheets[i]->GetFileName(); + + if( cmpFn.IsRelative() ) + cmpFn.MakeAbsolute( rootFn.GetPath() ); + + if( cmpFn == srcFn ) + return true; + + } while( i != 0 ); + + // The source sheet file name is not a parent of the destination sheet file name. + return false; +} + + +int SCH_SHEET_PATH::FindSheet( const wxString& aFileName ) const +{ + for( unsigned i = 0; i < m_numSheets; i++ ) + { + if( m_sheets[i]->GetFileName().CmpNoCase( aFileName ) == 0 ) + return (int)i; + } + + return SHEET_NOT_FOUND; +} + + +SCH_SHEET* SCH_SHEET_PATH::FindSheetByName( const wxString& aSheetName ) +{ + for( unsigned i = 0; i < m_numSheets; i++ ) + { + if( m_sheets[i]->GetName().CmpNoCase( aSheetName ) == 0 ) + return m_sheets[i]; + } + + return NULL; +} + + +/********************************************************************/ +/* Class SCH_SHEET_LIST to handle the list of Sheets in a hierarchy */ +/********************************************************************/ +SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet ) +{ + m_index = 0; + m_count = 0; + m_list = NULL; + m_isRootSheet = false; + + if( aSheet == NULL ) + aSheet = g_RootSheet; + + BuildSheetList( aSheet ); +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetFirst() +{ + m_index = 0; + + if( GetCount() > 0 ) + return &( m_list[0] ); + + return NULL; +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetNext() +{ + if( m_index < GetCount() ) + m_index++; + + return GetSheet( m_index ); +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetLast() +{ + if( GetCount() == 0 ) + return NULL; + + m_index = GetCount() - 1; + + return GetSheet( m_index ); +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetPrevious() +{ + if( m_index == 0 ) + return NULL; + + m_index -= 1; + + return GetSheet( m_index ); +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheet( int aIndex ) const +{ + if( aIndex < GetCount() ) + return &( m_list[aIndex] ); + + return NULL; +} + + +SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheetByPath( const wxString aPath, bool aHumanReadable ) +{ + SCH_SHEET_PATH* sheet = GetFirst(); + wxString sheetPath; + + while( sheet ) + { + sheetPath = ( aHumanReadable ) ? sheet->PathHumanReadable() : sheet->Path(); + + if( sheetPath == aPath ) + return sheet; + + sheet = GetNext(); + } + + return NULL; +} + + +void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet ) +{ + wxCHECK_RET( aSheet != NULL, wxT( "Cannot build sheet list from undefined sheet." ) ); + + if( aSheet == g_RootSheet ) + m_isRootSheet = true; + + if( m_list == NULL ) + { + int count = aSheet->CountSheets(); + + m_count = count; + m_index = 0; + m_list = new SCH_SHEET_PATH[ count ]; + m_currList.Clear(); + } + + m_currList.Push( aSheet ); + m_list[m_index] = m_currList; + m_index++; + + if( aSheet->GetScreen() ) + { + EDA_ITEM* strct = m_currList.LastDrawList(); + + while( strct ) + { + if( strct->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) strct; + BuildSheetList( sheet ); + } + + strct = strct->Next(); + } + } + + m_currList.Pop(); +} + + +bool SCH_SHEET_LIST::IsModified() +{ + for( SCH_SHEET_PATH* sheet = GetFirst(); sheet; sheet = GetNext() ) + { + if( sheet->LastScreen() && sheet->LastScreen()->IsModify() ) + return true; + } + + return false; +} + + +bool SCH_SHEET_LIST::IsAutoSaveRequired() +{ + for( SCH_SHEET_PATH* sheet = GetFirst(); sheet; sheet = GetNext() ) + { + if( sheet->LastScreen() && sheet->LastScreen()->IsSave() ) + return true; + } + + return false; +} + + +void SCH_SHEET_LIST::ClearModifyStatus() +{ + for( SCH_SHEET_PATH* sheet = GetFirst(); sheet; sheet = GetNext() ) + { + if( sheet->LastScreen() ) + sheet->LastScreen()->ClrModify(); + } +} + + +void SCH_SHEET_LIST::AnnotatePowerSymbols( PART_LIBS* aLibs ) +{ + int ref = 1; + + for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() ) + path->AnnotatePowerSymbols( aLibs, &ref ); +} + + +void SCH_SHEET_LIST::GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences, + bool aIncludePowerSymbols ) +{ + for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() ) + path->GetComponents( aLibs, aReferences, aIncludePowerSymbols ); +} + +void SCH_SHEET_LIST::GetMultiUnitComponents( PART_LIBS* aLibs, + SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols ) +{ + for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() ) + { + SCH_MULTI_UNIT_REFERENCE_MAP tempMap; + path->GetMultiUnitComponents( aLibs, tempMap ); + BOOST_FOREACH( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair, tempMap ) + { + // Merge this list into the main one + unsigned n_refs = pair.second.GetCount(); + for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef ) + { + aRefList[pair.first].AddItem( pair.second[thisRef] ); + } + } + } +} + + +SCH_ITEM* SCH_SHEET_LIST::FindNextItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn, + SCH_ITEM* aLastItem, bool aWrap ) +{ + bool hasWrapped = false; + bool firstItemFound = false; + + SCH_ITEM* drawItem = NULL; + SCH_SHEET_PATH* sheet = GetFirst(); + + while( sheet ) + { + drawItem = sheet->LastDrawList(); + + while( drawItem ) + { + if( drawItem->Type() == aType ) + { + if( aLastItem == NULL || firstItemFound ) + { + if( aSheetFoundIn ) + *aSheetFoundIn = sheet; + + return drawItem; + } + else if( !firstItemFound && drawItem == aLastItem ) + { + firstItemFound = true; + } + } + + drawItem = drawItem->Next(); + } + + sheet = GetNext(); + + if( sheet == NULL && aLastItem && aWrap && !hasWrapped ) + { + hasWrapped = true; + sheet = GetFirst(); + } + } + + return NULL; +} + + +SCH_ITEM* SCH_SHEET_LIST::FindPreviousItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFoundIn, + SCH_ITEM* aLastItem, bool aWrap ) +{ + bool hasWrapped = false; + bool firstItemFound = false; + SCH_ITEM* drawItem = NULL; + SCH_SHEET_PATH* sheet = GetLast(); + + while( sheet ) + { + drawItem = sheet->FirstDrawList(); + + while( drawItem ) + { + if( drawItem->Type() == aType ) + { + if( aLastItem == NULL || firstItemFound ) + { + if( aSheetFoundIn ) + *aSheetFoundIn = sheet; + + return drawItem; + } + else if( !firstItemFound && drawItem == aLastItem ) + { + firstItemFound = true; + } + } + + drawItem = drawItem->Back(); + } + + sheet = GetPrevious(); + + if( sheet == NULL && aLastItem && aWrap && !hasWrapped ) + { + hasWrapped = true; + sheet = GetLast(); + } + } + + return NULL; +} + + +bool SCH_SHEET_LIST::SetComponentFootprint( const wxString& aReference, + const wxString& aFootPrint, bool aSetVisible ) +{ + bool found = false; + + for( SCH_SHEET_PATH* path = GetFirst(); path; path = GetNext() ) + found = path->SetComponentFootprint( aReference, aFootPrint, aSetVisible ); + + return found; +} + + +bool SCH_SHEET_LIST::IsComplexHierarchy() const +{ + wxString fileName; + + for( int i = 0; i < m_count; i++ ) + { + fileName = m_list[i].Last()->GetFileName(); + + for( int j = 0; j < m_count; j++ ) + { + if( i == j ) + continue; + + if( fileName == m_list[j].Last()->GetFileName() ) + return true; + } + } + + return false; +} + + +bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy, + const wxString& aDestFileName ) const +{ + wxFileName rootFn = g_RootSheet->GetFileName(); + wxFileName destFn = aDestFileName; + + if( destFn.IsRelative() ) + destFn.MakeAbsolute( rootFn.GetPath() ); + + // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion. + for( int i = 0; i < m_count; i++ ) + { + // Test each SCH_SHEET_PATH in the source sheet. + for( int j = 0; j < aSrcSheetHierarchy.GetCount(); j++ ) + { + SCH_SHEET_PATH* sheetPath = aSrcSheetHierarchy.GetSheet( j ); + + for( unsigned k = 0; k < sheetPath->GetCount(); k++ ) + { + if( m_list[i].TestForRecursion( sheetPath->GetSheet( k )->GetFileName(), + aDestFileName ) ) + return true; + } + } + } + + // The source sheet file can safely be added to the destination sheet file. + return false; +} + + +SCH_SHEET* SCH_SHEET_LIST::FindSheetByName( const wxString& aSheetName ) +{ + for( int i = 0; i < m_count; i++ ) + { + SCH_SHEET* sheet = m_list[i].FindSheetByName( aSheetName ); + + if( sheet ) + return sheet; + } + + return NULL; +} diff --git a/eeschema/sch_sheet_path.h b/eeschema/sch_sheet_path.h new file mode 100644 index 00000000..939d899a --- /dev/null +++ b/eeschema/sch_sheet_path.h @@ -0,0 +1,571 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_sheet_path.h + * @brief Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema. + */ + +#ifndef CLASS_DRAWSHEET_PATH_H +#define CLASS_DRAWSHEET_PATH_H + +#include + + +/** Info about complex hierarchies handling: + * A hierarchical schematic uses sheets (hierarchical sheets) included in a + * given sheet. Each sheet corresponds to a schematic drawing handled by a + * SCH_SCREEN structure. A SCH_SCREEN structure contains drawings, and have + * a filename to write it's data. Also a SCH_SCREEN display a sheet number + * and the name of the sheet. + * + * In simple (and flat) hierarchies a sheet is linked to a SCH_SCREEN, + * and a SCH_SCREEN is used by only one hierarchical sheet. + * + * In complex hierarchies the same SCH_SCREEN (and its data) is shared between + * more than one sheet. Therefore subsheets (like subsheets in a SCH_SCREEN + * shared by many sheets) can be also shared. So the same SCH_SCREEN must + * handle different components references and parts selection depending on + * which sheet is currently selected, and how a given subsheet is selected. + * 2 sheets share the same SCH_SCREEN (the same drawings) if they have the + * same filename. + * + * In KiCad each component and sheet receives (when created) an unique + * identification called Time Stamp. So each sheet has 2 ids: its time stamp + * (that cannot change) and its name ( that can be edited and therefore is + * not reliable for strong identification). KiCad uses Time Stamp ( a unique + * 32 bit id), to identify sheets in hierarchies. + * A given sheet in a hierarchy is fully labeled by its path (or sheet path) + * that is the list of time stamp found to access it through the hierarchy + * the root sheet is /. All other sheets have a path like /1234ABCD or + * /4567FEDC/AA2233DD/. This path can be displayed as human readable sheet + * name like: / or /sheet1/include_sheet/ or /sheet2/include_sheet/ + * + * So to know for a given SCH_SCREEN (a given schematic drawings) we must: + * 1) Handle all references possibilities. + * 2) When acceded by a given selected sheet, display (update) the + * corresponding references and sheet path + * + * The class SCH_SHEET_PATH handles paths used to access a sheet. The class + * SCH_SHEET_LIST allows to handle the full (or partial) list of sheets and + * their paths in a complex hierarchy. The class EDA_ScreenList allow to + * handle the list of SCH_SCREEN. It is useful to clear or save data, + * but is not suitable to handle the full complex hierarchy possibilities + * (usable in flat and simple hierarchies). + */ + + +class wxFindReplaceData; +class SCH_SCREEN; +class SCH_MARKER; +class SCH_SHEET; +class SCH_ITEM; +class SCH_REFERENCE_LIST; +class PART_LIBS; + +#define SHEET_NOT_FOUND -1 + + +/** + * Type SCH_MULTI_UNIT_REFERENCE_MAP + * is used to create a map of reference designators for multi-unit parts. + */ +typedef std::map SCH_MULTI_UNIT_REFERENCE_MAP; + +/** + * Class SCH_SHEET_PATH + * handles access to a sheet by way of a path. + *

      + * The member m_sheets stores the list of sheets from the first (usually + * g_RootSheet) to a given sheet in last position. + * The _last_ sheet is usually the sheet we want to select or reach (which is + * what the function Last() returns). + * Others sheets constitute the "path" from the first to the last sheet. + *

      + */ +class SCH_SHEET_PATH +{ +#define DSLSZ 32 // Max number of levels for a sheet path + + SCH_SHEET* m_sheets[ DSLSZ ]; + unsigned m_numSheets; + +public: + SCH_SHEET_PATH(); + + void Clear() + { + m_numSheets = 0; + } + + unsigned GetCount() + { + return m_numSheets; + } + + SCH_SHEET* GetSheet( unsigned index ) + { + if( index < m_numSheets ) + return m_sheets[index]; + + return NULL; + } + + /** + * Function Cmp + * Compare if this is the same sheet path as aSheetPathToTest + * @param aSheetPathToTest = sheet path to compare + * @return 1 if this sheet path has more sheets than aSheetPathToTest, + * -1 if this sheet path has fewer sheets than aSheetPathToTest, + * or 0 if same + */ + int Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const; + + /** + * Function Last + * returns a pointer to the last sheet of the list + * One can see the others sheet as the "path" to reach this last sheet + */ + SCH_SHEET* Last() const; + + /** + * Function LastScreen + * @return the SCH_SCREEN relative to the last sheet in list + */ + SCH_SCREEN* LastScreen() const; + + /** + * Function LastDrawList + * @return a pointer to the first schematic item handled by the + * SCH_SCREEN relative to the last sheet in list + */ + SCH_ITEM* LastDrawList() const; + + /** + * Get the last schematic item relative to the first sheet in the list. + * + * @return Last schematic item relative to the first sheet in the list if list + * is not empty. Otherwise NULL. + */ + SCH_ITEM* FirstDrawList() const; + + /** + * Function Push + * store (push) aSheet in list + * @param aSheet = pointer to the SCH_SHEET to store in list + * Push is used when entered a sheet to select or analyze it + * This is like cd <directory> in directories navigation + */ + void Push( SCH_SHEET* aSheet ); + + /** + * Function Pop + * retrieves (pop) the last entered sheet and remove it from list + * @return a SCH_SHEET* pointer to the removed sheet in list + * Pop is used when leaving a sheet after a selection or analyze + * This is like cd .. in directories navigation + */ + SCH_SHEET* Pop(); + + /** + * Function Path + * the path uses the time stamps which do not changes even when editing + * sheet parameters + * a path is something like / (root) or /34005677 or /34005677/00AE4523 + */ + wxString Path() const; + + /** + * Function PathHumanReadable + * returns the sheet path in a human readable form, i.e. as a path made + * from sheet names. The the "normal" path instead uses the time + * stamps in the path. (Time stamps do not change even when editing + * sheet parameters). + */ + wxString PathHumanReadable() const; + + /** + * Function BuildSheetPathInfoFromSheetPathValue + * Fill this with data to access to the hierarchical sheet known by its path \a aPath + * @param aPath = path of the sheet to reach (in non human readable format) + * @param aFound - Please document me. + * @return true if success else false + */ + bool BuildSheetPathInfoFromSheetPathValue( const wxString& aPath, bool aFound = false ); + + /** + * Function UpdateAllScreenReferences + * updates the reference and the m_Multi parameter (part selection) for all + * components on a screen depending on the actual sheet path. + * Mandatory in complex hierarchies because sheets use the same screen + * (basic schematic) + * but with different references and part selections according to the + * displayed sheet + */ + void UpdateAllScreenReferences(); + + /** + * Function AnnotatePowerSymbols + * annotates the power symbols only starting at \a aReference in the sheet path. + * @param aLibs the library list to use + * @param aReference A pointer to the number for the reference designator of the + * first power symbol to be annotated. If the pointer is NULL + * the annotation starts at 1. The number is incremented for + * each power symbol annotated. + */ + void AnnotatePowerSymbols( PART_LIBS* aLibs, int* aReference ); + + /** + * Function GetComponents + * adds a SCH_REFERENCE() object to \a aReferences for each component in the sheet. + * @param aLibs the library list to use + * @param aReferences List of references to populate. + * @param aIncludePowerSymbols : false to only get normal components. + */ + void GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences, + bool aIncludePowerSymbols = true ); + + /** + * Function GetMultiUnitComponents + * adds a SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of + * multi-unit parts in the sheet. The map key for each element will be the + * reference designator. + * @param aLibs the library list to use + * @param aRefList Map of reference designators to reference lists + * @param aIncludePowerSymbols : false to only get normal components. + */ + void GetMultiUnitComponents( PART_LIBS* aLibs, SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, + bool aIncludePowerSymbols = true ); + + /** + * Function SetFootprintField + * searches last sheet in the path for a component with \a aReference and set the footprint + * field to \a aFootPrint if found. + * + * @param aReference The reference designator of the component. + * @param aFootPrint The value to set the footprint field. + * @param aSetVisible The value to set the field visibility flag. + * @return True if \a aReference was found otherwise false. + */ + bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint, + bool aSetVisible ); + + /** + * Find the next schematic item in this sheet object. + * + * @param aType - The type of schematic item object to search for. + * @param aLastItem - Start search from aLastItem. If no aLastItem, search from + * the beginning of the list. + * @param aWrap - Wrap around the end of the list to find the next item if aLastItem + * is defined. + * @return - The next schematic item if found. Otherwise, NULL is returned. + */ + SCH_ITEM* FindNextItem( KICAD_T aType, SCH_ITEM* aLastItem = NULL, bool aWrap = false ) const; + + /** + * Find the previous schematic item in this sheet path object. + * + * @param aType - The type of schematic item object to search for. + * @param aLastItem - Start search from aLastItem. If no aLastItem, search from + * the end of the list. + * @param aWrap - Wrap around the beginning of the list to find the next item if aLastItem + * is defined. + * @return - The previous schematic item if found. Otherwise, NULL is returned. + */ + SCH_ITEM* FindPreviousItem( KICAD_T aType, SCH_ITEM* aLastItem = NULL, bool aWrap = false ) const; + + /** + * Function TestForRecursion + * + * test the SCH_SHEET_PATH file names to check adding the sheet stored in the file + * \a aSrcFileName to the sheet stored in file \a aDestFileName will cause a sheet + * path recursion. + * + * @param aSrcFileName is the source file name of the sheet add to \a aDestFileName. + * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName. + * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false. + */ + bool TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName ) const; + + int FindSheet( const wxString& aFileName ) const; + + /** + * Function FindSheetByName + * + * searches the #SCH_SHEET_PATH for a sheet named \a aSheetName. + * + * @param aSheetName is the name of the sheet to find. + * @return a pointer to the sheet named \a aSheetName if found or NULL if not found. + */ + SCH_SHEET* FindSheetByName( const wxString& aSheetName ); + + SCH_SHEET_PATH& operator=( const SCH_SHEET_PATH& d1 ); + + bool operator==( const SCH_SHEET_PATH& d1 ) const; + + bool operator!=( const SCH_SHEET_PATH& d1 ) const { return !( *this == d1 ) ; } +}; + + +/** + * Class SCH_SHEET_LIST + * handles the list of Sheets in a hierarchy. + * Sheets are not unique, there can be many sheets with the same + * filename and the same SCH_SCREEN reference. + * The schematic (SCH_SCREEN) is shared between these sheets, + * and component references are specific to a sheet path. + * When a sheet is entered, component references and sheet number are updated. + */ +class SCH_SHEET_LIST +{ +private: + SCH_SHEET_PATH* m_list; + int m_count; /* Number of sheets included in hierarchy, + * starting at the given sheet in constructor . + * the given sheet is counted + */ + int m_index; /* internal variable to handle GetNext(): cleared by + * GetFirst() and incremented by GetNext() after + * returning the next item in m_list. Also used for + * internal calculations in BuildSheetList() + */ + bool m_isRootSheet; + SCH_SHEET_PATH m_currList; + +public: + + /** + * Constructor + * builds the list of sheets from aSheet. + * If aSheet == NULL (default) build the whole list of sheets in hierarchy. + * So usually call it with no parameter. + */ + SCH_SHEET_LIST( SCH_SHEET* aSheet = NULL ); + + ~SCH_SHEET_LIST() + { + if( m_list ) + delete[] m_list; + + m_list = NULL; + } + + /** + * Function GetCount + * @return the number of sheets in list: + * usually the number of sheets found in the whole hierarchy + */ + int GetCount() const { return m_count; } + + /** + * Function GetIndex + * @return the last selected screen index. + */ + int GetIndex() const { return m_index; } + + /** + * Function GetFirst + * @return the first item (sheet) in m_list and prepare calls to GetNext() + */ + SCH_SHEET_PATH* GetFirst(); + + /** + * Function GetNext + * @return the next item (sheet) in m_list or NULL if no more item in + * sheet list + */ + SCH_SHEET_PATH* GetNext(); + + /** + * Function GetLast + * returns the last sheet in the sheet list. + * + * @return Last sheet in the list or NULL if sheet list is empty. + */ + SCH_SHEET_PATH* GetLast(); + + /** + * Function GetPrevious + * returns the previous sheet in the sheet list. + * + * @return The previous sheet in the sheet list or NULL if already at the + * beginning of the list. + */ + SCH_SHEET_PATH* GetPrevious(); + + /** + * Function GetSheet + * + * @param aIndex A index in sheet list to get the sheet. + * @return the sheet at \a aIndex position in m_list or NULL if \a aIndex is + * outside the bounds of the index list. + */ + SCH_SHEET_PATH* GetSheet( int aIndex ) const; + + /** + * Function GetSheetByPath + * returns a sheet matching the path name in \a aPath. + * + * @param aPath A wxString object containing path of the sheet to get. + * @param aHumanReadable True uses the human readable path for comparison. + * False uses the timestamp generated path. + * @return The sheet that matches \a aPath or NULL if no sheet matching + * \a aPath is found. + */ + SCH_SHEET_PATH* GetSheetByPath( const wxString aPath, bool aHumanReadable = true ); + + /** + * Function IsModified + * checks the entire hierarchy for any modifications. + * @returns True if the hierarchy is modified otherwise false. + */ + bool IsModified(); + + /** + * Function IsAutoSaveRequired + * checks the entire hierarchy for any modifications that require auto save. + * @return True if the hierarchy is modified otherwise false. + */ + bool IsAutoSaveRequired(); + + void ClearModifyStatus(); + + /** + * Function AnnotatePowerSymbols + * clear and annotates the entire hierarchy of the sheet path list. + * @param aLib the library list to use + */ + void AnnotatePowerSymbols( PART_LIBS* aLib ); + + /** + * Function GetComponents + * adds a SCH_REFERENCE() object to \a aReferences for each component in the list + * of sheets. + * @param aLibs the library list to use + * @param aReferences List of references to populate. + * @param aIncludePowerSymbols Set to false to only get normal components. + */ + void GetComponents( PART_LIBS* aLibs, SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols = true ); + + /** + * Function GetMultiUnitComponents + * adds a SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of + * multi-unit parts in the list of sheets. The map key for each element will be the + * reference designator. + * @param aLibs the library list to use + * @param aRefList Map of reference designators to reference lists + * @param aIncludePowerSymbols Set to false to only get normal components. + */ + void GetMultiUnitComponents( PART_LIBS* aLibs, SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, + bool aIncludePowerSymbols = true ); + + /** + * Function FindNextItem + * searches the entire schematic for the next schematic object. + * + * @param aType - The type of schematic item to find. + * @param aSheetFound - The sheet the item was found in. NULL if the next item + * is not found. + * @param aLastItem - Find next item after aLastItem if not NULL. + * @param aWrap - Wrap past around the end of the list of sheets. + * @return If found, Returns the next schematic item. Otherwise, returns NULL. + */ + SCH_ITEM* FindNextItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFound = NULL, + SCH_ITEM* aLastItem = NULL, bool aWrap = true ); + + /** + * Function FindPreviousItem + * searches the entire schematic for the previous schematic item. + * + * @param aType - The type of schematic item to find. + * @param aSheetFound - The sheet the item was found in. NULL if the previous item + * is not found. + * @param aLastItem - Find the previous item before aLastItem if not NULL. + * @param aWrap - Wrap past around the beginning of the list of sheets. + * @return If found, the previous schematic item. Otherwise, NULL. + */ + SCH_ITEM* FindPreviousItem( KICAD_T aType, SCH_SHEET_PATH** aSheetFound = NULL, + SCH_ITEM* aLastItem = NULL, bool aWrap = true ); + + /** + * Function SetFootprintField + * searches all the sheets for a component with \a aReference and set the footprint + * field to \a aFootPrint if found. + * + * @param aReference The reference designator of the component. + * @param aFootPrint The value to set the footprint field. + * @param aSetVisible The value to set the field visibility flag. + * @return True if \a aReference was found otherwise false. + */ + bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint, + bool aSetVisible ); + + /** + * Function IsComplexHierarchy + * searches all of the sheets for duplicate files names which indicates a complex + * hierarchy. + * + * @return true if the #SCH_SHEET_LIST is a complex hierarchy. + */ + bool IsComplexHierarchy() const; + + /** + * Function TestForRecursion + * + * test every SCH_SHEET_PATH in the SCH_SHEET_LIST to verify if adding the sheets stored + * in \a aSrcSheetHierarchy to the sheet stored in \a aDestFileName will cause recursion. + * + * @param aSrcSheetHierarchy is the SCH_SHEET_LIST of the source sheet add to \a aDestFileName. + * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName. + * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false. + */ + bool TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy, + const wxString& aDestFileName ) const; + + /** + * Function FindSheetByName + * + * searches the entire #SCH_SHEET_LIST for a sheet named \a aSheetName. + * + * @param aSheetName is the name of the sheet to find. + * @return a pointer to the sheet named \a aSheetName if found or NULL if not found. + */ + SCH_SHEET* FindSheetByName( const wxString& aSheetName ); + +private: + + /** + * Function BuildSheetList + * builds the list of sheets and their sheet path from \a aSheet. + * If \a aSheet is the root sheet, the full sheet path and sheet list are built. + * + * @param aSheet is the starting sheet from which the list is built, or NULL + * indicating that g_RootSheet should be used. + * @throw std::bad_alloc if the memory for the sheet path list could not be allocated. + */ + void BuildSheetList( SCH_SHEET* aSheet ); +}; + +#endif // CLASS_DRAWSHEET_PATH_H diff --git a/eeschema/sch_sheet_pin.cpp b/eeschema/sch_sheet_pin.cpp new file mode 100644 index 00000000..b4c76977 --- /dev/null +++ b/eeschema/sch_sheet_pin.cpp @@ -0,0 +1,526 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2011 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 + */ + +/** + * @file sch_sheet_pin.cpp + * @brief Implementation of the SCH_SHEET_PIN class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +SCH_SHEET_PIN::SCH_SHEET_PIN( SCH_SHEET* parent, const wxPoint& pos, const wxString& text ) : + SCH_HIERLABEL( pos, text, SCH_SHEET_PIN_T ) +{ + SetParent( parent ); + wxASSERT( parent ); + m_Layer = LAYER_SHEETLABEL; + m_Pos = pos; + + if( parent->IsVerticalOrientation() ) + SetEdge( SHEET_TOP_SIDE ); + else + SetEdge( SHEET_LEFT_SIDE ); + + m_shape = NET_INPUT; + m_isDangling = true; + m_number = 2; +} + + +EDA_ITEM* SCH_SHEET_PIN::Clone() const +{ + return new SCH_SHEET_PIN( *this ); +} + + +void SCH_SHEET_PIN::Draw( EDA_DRAW_PANEL* aPanel, + wxDC* aDC, + const wxPoint& aOffset, + GR_DRAWMODE aDraw_mode, + EDA_COLOR_T aColor ) +{ + // The icon selection is handle by the virtual method CreateGraphicShape + // called by ::Draw + SCH_HIERLABEL::Draw( aPanel, aDC, aOffset, aDraw_mode, aColor ); +} + + +void SCH_SHEET_PIN::SwapData( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem->Type() == SCH_SHEET_PIN_T, + wxString::Format( wxT( "SCH_SHEET_PIN object cannot swap data with %s object." ), + GetChars( aItem->GetClass() ) ) ); + + SCH_SHEET_PIN* pin = ( SCH_SHEET_PIN* ) aItem; + SCH_TEXT::SwapData( (SCH_TEXT*) pin ); + int tmp = pin->GetNumber(); + pin->SetNumber( GetNumber() ); + SetNumber( tmp ); + SHEET_SIDE stmp = pin->GetEdge(); + pin->SetEdge( GetEdge() ); + SetEdge( stmp ); +} + + +bool SCH_SHEET_PIN::operator==( const SCH_SHEET_PIN* aPin ) const +{ + return aPin == this; +} + + +int SCH_SHEET_PIN::GetPenSize() const +{ + return GetDefaultLineThickness(); +} + + +void SCH_SHEET_PIN::SetNumber( int aNumber ) +{ + wxASSERT( aNumber >= 2 ); + + m_number = aNumber; +} + + +void SCH_SHEET_PIN::SetEdge( SCH_SHEET_PIN::SHEET_SIDE aEdge ) +{ + SCH_SHEET* Sheet = GetParent(); + + // use SHEET_UNDEFINED_SIDE to adjust text orientation without changing edge + + switch( aEdge ) + { + case SHEET_LEFT_SIDE: + m_edge = aEdge; + m_Pos.x = Sheet->m_pos.x; + SetOrientation( 2 ); /* Orientation horiz inverse */ + break; + + case SHEET_RIGHT_SIDE: + m_edge = aEdge; + m_Pos.x = Sheet->m_pos.x + Sheet->m_size.x; + SetOrientation( 0 ); /* Orientation horiz normal */ + break; + + case SHEET_TOP_SIDE: + m_edge = aEdge; + m_Pos.y = Sheet->m_pos.y; + SetOrientation( 3 ); /* Orientation vert BOTTOM */ + break; + + case SHEET_BOTTOM_SIDE: + m_edge = aEdge; + m_Pos.y = Sheet->m_pos.y + Sheet->m_size.y; + SetOrientation( 1 ); /* Orientation vert UP */ + break; + + default: + break; + } +} + + +enum SCH_SHEET_PIN::SHEET_SIDE SCH_SHEET_PIN::GetEdge() const +{ + return m_edge; +} + + +void SCH_SHEET_PIN::ConstrainOnEdge( wxPoint Pos ) +{ + SCH_SHEET* sheet = GetParent(); + + if( sheet == NULL ) + return; + + wxPoint center = sheet->m_pos + ( sheet->m_size / 2 ); + + if( m_edge == SHEET_LEFT_SIDE || m_edge == SHEET_RIGHT_SIDE ) + { + if( Pos.x > center.x ) + { + SetEdge( SHEET_RIGHT_SIDE ); + } + else + { + SetEdge( SHEET_LEFT_SIDE ); + } + + m_Pos.y = Pos.y; + + if( m_Pos.y < sheet->m_pos.y ) + m_Pos.y = sheet->m_pos.y; + + if( m_Pos.y > (sheet->m_pos.y + sheet->m_size.y) ) + m_Pos.y = sheet->m_pos.y + sheet->m_size.y; + } + else /* vertical sheetpin*/ + { + if( Pos.y > center.y ) + { + SetEdge( SHEET_BOTTOM_SIDE ); //bottom + } + else + { + SetEdge( SHEET_TOP_SIDE ); //top + } + + m_Pos.x = Pos.x; + + if( m_Pos.x < sheet->m_pos.x ) + m_Pos.x = sheet->m_pos.x; + + if( m_Pos.x > (sheet->m_pos.x + sheet->m_size.x) ) + m_Pos.x = sheet->m_pos.x + sheet->m_size.x; + } +} + + +bool SCH_SHEET_PIN::Save( FILE* aFile ) const +{ + int type = 'U', side = 'L'; + + if( m_Text.IsEmpty() ) + return true; + + switch( m_edge ) + { + default: + case SHEET_LEFT_SIDE: //pin on left side + side = 'L'; + break; + + case SHEET_RIGHT_SIDE: //pin on right side + side = 'R'; + break; + + case SHEET_TOP_SIDE: //pin on top side + side = 'T'; + break; + + case SHEET_BOTTOM_SIDE: //pin on bottom side + side = 'B'; + break; + } + + switch( m_shape ) + { + case NET_INPUT: + type = 'I'; break; + + case NET_OUTPUT: + type = 'O'; break; + + case NET_BIDI: + type = 'B'; break; + + case NET_TRISTATE: + type = 'T'; break; + + case NET_UNSPECIFIED: + type = 'U'; break; + } + + if( fprintf( aFile, "F%d %s %c %c %-3d %-3d %-3d\n", m_number, + EscapedUTF8( m_Text ).c_str(), // supplies wrapping quotes + type, side, m_Pos.x, m_Pos.y, + m_Size.x ) == EOF ) + { + return false; + } + + return true; +} + + +bool SCH_SHEET_PIN::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + int size; + char number[256]; + char name[256]; + char connectType[256]; + char sheetSide[256]; + char* line = aLine.Line(); + char* cp; + + static const char delims[] = " \t"; + + // Read coordinates. + // D( printf( "line: \"%s\"\n", line );) + + cp = strtok( line, delims ); + + strncpy( number, cp, sizeof(number) ); + number[sizeof(number)-1] = 0; + + cp += strlen( number ) + 1; + + cp += ReadDelimitedText( name, cp, sizeof(name) ); + + cp = strtok( cp, delims ); + strncpy( connectType, cp, sizeof(connectType) ); + connectType[sizeof(connectType)-1] = 0; + + cp = strtok( NULL, delims ); + strncpy( sheetSide, cp, sizeof(sheetSide) ); + sheetSide[sizeof(sheetSide)-1] = 0; + + cp += strlen( sheetSide ) + 1; + + int r = sscanf( cp, "%d %d %d", &m_Pos.x, &m_Pos.y, &size ); + if( r != 3 ) + { + aErrorMsg.Printf( wxT( "Eeschema file sheet hierarchical label error at line %d.\n" ), + aLine.LineNumber() ); + + aErrorMsg << FROM_UTF8( line ); + return false; + } + + m_Text = FROM_UTF8( name ); + + if( size == 0 ) + size = GetDefaultTextSize(); + + m_Size.x = m_Size.y = size; + + switch( connectType[0] ) + { + case 'I': + m_shape = NET_INPUT; + break; + + case 'O': + m_shape = NET_OUTPUT; + break; + + case 'B': + m_shape = NET_BIDI; + break; + + case 'T': + m_shape = NET_TRISTATE; + break; + + case 'U': + m_shape = NET_UNSPECIFIED; + break; + } + + switch( sheetSide[0] ) + { + case 'R' : /* pin on right side */ + SetEdge( SHEET_RIGHT_SIDE ); + break; + + case 'T' : /* pin on top side */ + SetEdge( SHEET_TOP_SIDE ); + break; + + case 'B' : /* pin on bottom side */ + SetEdge( SHEET_BOTTOM_SIDE ); + break; + + case 'L' : /* pin on left side */ + default : + SetEdge( SHEET_LEFT_SIDE ); + break; + } + + return true; +} + + +bool SCH_SHEET_PIN::Matches( wxFindReplaceData& aSearchData, + void* aAuxData, wxPoint* aFindLocation ) +{ + wxCHECK_MSG( GetParent() != NULL, false, + wxT( "Sheet pin " ) + m_Text + wxT( " does not have a parent sheet!" ) ); + + wxLogTrace( traceFindItem, wxT( " child item " ) + GetSelectMenuText() ); + + if( SCH_ITEM::Matches( m_Text, aSearchData ) ) + { + if( aFindLocation ) + *aFindLocation = GetBoundingBox().Centre(); + + return true; + } + + return false; +} + + +void SCH_SHEET_PIN::MirrorX( int aXaxis_position ) +{ + int p = m_Pos.y - aXaxis_position; + + m_Pos.y = aXaxis_position - p; + + switch( m_edge ) + { + case SHEET_TOP_SIDE: + SetEdge( SHEET_BOTTOM_SIDE ); + break; + + case SHEET_BOTTOM_SIDE: + SetEdge( SHEET_TOP_SIDE ); + break; + + default: + break; + } +} + + +void SCH_SHEET_PIN::MirrorY( int aYaxis_position ) +{ + int p = m_Pos.x - aYaxis_position; + + m_Pos.x = aYaxis_position - p; + + switch( m_edge ) + { + case SHEET_LEFT_SIDE: + SetEdge( SHEET_RIGHT_SIDE ); + break; + + case SHEET_RIGHT_SIDE: + SetEdge( SHEET_LEFT_SIDE ); + break; + + default: + break; + } +} + + +void SCH_SHEET_PIN::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); + + switch( m_edge ) + { + case SHEET_LEFT_SIDE: //pin on left side + SetEdge( SHEET_BOTTOM_SIDE ); + break; + + case SHEET_RIGHT_SIDE: //pin on right side + SetEdge( SHEET_TOP_SIDE ); + break; + + case SHEET_TOP_SIDE: //pin on top side + SetEdge( SHEET_LEFT_SIDE ); + break; + + case SHEET_BOTTOM_SIDE: //pin on bottom side + SetEdge( SHEET_RIGHT_SIDE ); + break; + + default: + break; + } +} + + +void SCH_SHEET_PIN::CreateGraphicShape( std::vector & aPoints, const wxPoint& aPos ) +{ + /* This is the same icon shapes as SCH_HIERLABEL + * but the graphic icon is slightly different in 2 cases: + * for INPUT type the icon is the OUTPUT shape of SCH_HIERLABEL + * for OUTPUT type the icon is the INPUT shape of SCH_HIERLABEL + */ + int tmp = m_shape; + + switch( m_shape ) + { + case NET_INPUT: + m_shape = NET_OUTPUT; + break; + + case NET_OUTPUT: + m_shape = NET_INPUT; + break; + + default: + break; + } + + SCH_HIERLABEL::CreateGraphicShape( aPoints, aPos ); + m_shape = tmp; +} + + +void SCH_SHEET_PIN::GetEndPoints( std::vector & aItemList ) +{ + DANGLING_END_ITEM item( SHEET_LABEL_END, this, m_Pos ); + aItemList.push_back( item ); +} + + +wxString SCH_SHEET_PIN::GetSelectMenuText() const +{ + wxString tmp; + tmp.Printf( _( "Hierarchical Sheet Pin %s" ), GetChars( ShortenedShownText() ) ); + return tmp; +} + + +bool SCH_SHEET_PIN::HitTest( const wxPoint& aPoint, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPoint ); +} + + +#if defined(DEBUG) + +void SCH_SHEET_PIN::Show( int nestLevel, std::ostream& os ) const +{ + // XML output: + wxString s = GetClass(); + + NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << ">" + << " pin_name=\"" << TO_UTF8( m_Text ) + << '"' << "/>\n" << std::flush; + +// NestedSpace( nestLevel, os ) << "\n"; +} + +#endif diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp new file mode 100644 index 00000000..c84852c3 --- /dev/null +++ b/eeschema/sch_text.cpp @@ -0,0 +1,1777 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_text.cpp + * @brief Code for handling schematic sheet labels. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +extern void IncrementLabelMember( wxString& name, int aIncrement ); + + +/* Names of sheet label types. */ +const char* SheetLabelType[] = +{ + "Input", + "Output", + "BiDi", + "3State", + "UnSpc", + "???" +}; + +/* Coding polygons for global symbol graphic shapes. + * the first parml is the number of corners + * others are the corners coordinates in reduced units + * the real coordinate is the reduced coordinate * text half size + */ +static int TemplateIN_HN[] = { 6, 0, 0, -1, -1, -2, -1, -2, 1, -1, 1, 0, 0 }; +static int TemplateIN_HI[] = { 6, 0, 0, 1, 1, 2, 1, 2, -1, 1, -1, 0, 0 }; +static int TemplateIN_UP[] = { 6, 0, 0, 1, -1, 1, -2, -1, -2, -1, -1, 0, 0 }; +static int TemplateIN_BOTTOM[] = { 6, 0, 0, 1, 1, 1, 2, -1, 2, -1, 1, 0, 0 }; + +static int TemplateOUT_HN[] = { 6, -2, 0, -1, 1, 0, 1, 0, -1, -1, -1, -2, 0 }; +static int TemplateOUT_HI[] = { 6, 2, 0, 1, -1, 0, -1, 0, 1, 1, 1, 2, 0 }; +static int TemplateOUT_UP[] = { 6, 0, -2, 1, -1, 1, 0, -1, 0, -1, -1, 0, -2 }; +static int TemplateOUT_BOTTOM[] = { 6, 0, 2, 1, 1, 1, 0, -1, 0, -1, 1, 0, 2 }; + +static int TemplateUNSPC_HN[] = { 5, 0, -1, -2, -1, -2, 1, 0, 1, 0, -1 }; +static int TemplateUNSPC_HI[] = { 5, 0, -1, 2, -1, 2, 1, 0, 1, 0, -1 }; +static int TemplateUNSPC_UP[] = { 5, 1, 0, 1, -2, -1, -2, -1, 0, 1, 0 }; +static int TemplateUNSPC_BOTTOM[] = { 5, 1, 0, 1, 2, -1, 2, -1, 0, 1, 0 }; + +static int TemplateBIDI_HN[] = { 5, 0, 0, -1, -1, -2, 0, -1, 1, 0, 0 }; +static int TemplateBIDI_HI[] = { 5, 0, 0, 1, -1, 2, 0, 1, 1, 0, 0 }; +static int TemplateBIDI_UP[] = { 5, 0, 0, -1, -1, 0, -2, 1, -1, 0, 0 }; +static int TemplateBIDI_BOTTOM[] = { 5, 0, 0, -1, 1, 0, 2, 1, 1, 0, 0 }; + +static int Template3STATE_HN[] = { 5, 0, 0, -1, -1, -2, 0, -1, 1, 0, 0 }; +static int Template3STATE_HI[] = { 5, 0, 0, 1, -1, 2, 0, 1, 1, 0, 0 }; +static int Template3STATE_UP[] = { 5, 0, 0, -1, -1, 0, -2, 1, -1, 0, 0 }; +static int Template3STATE_BOTTOM[] = { 5, 0, 0, -1, 1, 0, 2, 1, 1, 0, 0 }; + +static int* TemplateShape[5][4] = +{ + { TemplateIN_HN, TemplateIN_UP, TemplateIN_HI, TemplateIN_BOTTOM }, + { TemplateOUT_HN, TemplateOUT_UP, TemplateOUT_HI, TemplateOUT_BOTTOM }, + { TemplateBIDI_HN, TemplateBIDI_UP, TemplateBIDI_HI, TemplateBIDI_BOTTOM }, + { Template3STATE_HN, Template3STATE_UP, Template3STATE_HI, Template3STATE_BOTTOM }, + { TemplateUNSPC_HN, TemplateUNSPC_UP, TemplateUNSPC_HI, TemplateUNSPC_BOTTOM } +}; + + +SCH_TEXT::SCH_TEXT( const wxPoint& pos, const wxString& text, KICAD_T aType ) : + SCH_ITEM( NULL, aType ), + EDA_TEXT( text ) +{ + m_Layer = LAYER_NOTES; + m_Pos = pos; + m_shape = 0; + m_isDangling = false; + m_MultilineAllowed = true; + m_schematicOrientation = 0; +} + + +SCH_TEXT::SCH_TEXT( const SCH_TEXT& aText ) : + SCH_ITEM( aText ), + EDA_TEXT( aText ) +{ + m_Pos = aText.m_Pos; + m_shape = aText.m_shape; + m_MultilineAllowed = aText.m_MultilineAllowed; + m_schematicOrientation = aText.m_schematicOrientation; + m_isDangling = false; +} + + +EDA_ITEM* SCH_TEXT::Clone() const +{ + return new SCH_TEXT( *this ); +} + + +void SCH_TEXT::IncrementLabel( int aIncrement ) +{ + IncrementLabelMember( m_Text, aIncrement ); +} + + +wxPoint SCH_TEXT::GetSchematicTextOffset() const +{ + wxPoint text_offset; + + // add a small offset (TXTMARGE) to x ( or y) position to allow a text to + // be on a wire or a line and be readable + switch( m_schematicOrientation ) + { + default: + case 0: /* Horiz Normal Orientation (left justified) */ + text_offset.y = -TXTMARGE; + break; + + case 1: /* Vert Orientation UP */ + text_offset.x = -TXTMARGE; + break; + + case 2: /* Horiz Orientation - Right justified */ + text_offset.y = -TXTMARGE; + break; + + case 3: /* Vert Orientation BOTTOM */ + text_offset.x = -TXTMARGE; + break; + } + + return text_offset; +} + + +bool SCH_TEXT::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint * aFindLocation ) +{ + wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText() ); + + if( SCH_ITEM::Matches( m_Text, aSearchData ) ) + { + EDA_RECT BoundaryBox = GetBoundingBox(); + + if( aFindLocation ) + *aFindLocation = BoundaryBox.Centre(); + + return true; + } + + return false; +} + + +void SCH_TEXT::MirrorY( int aYaxis_position ) +{ + // Text is NOT really mirrored; it is moved to a suitable horizontal position + switch( GetOrientation() ) + { + case 0: // horizontal text + SetOrientation( 2 ); + break; + + case 2: // invert horizontal text + SetOrientation( 0 ); + break; + + case 1: // Vert Orientation UP + case 3: // Vert Orientation BOTTOM + default: + break; + } + + MIRROR( m_Pos.x, aYaxis_position ); +} + + +void SCH_TEXT::MirrorX( int aXaxis_position ) +{ + // Text is NOT really mirrored; it is moved to a suitable vertical position + switch( GetOrientation() ) + { + case 1: // Vert Orientation UP + SetOrientation( 3 ); + break; + + case 3: // Vert Orientation BOTTOM + SetOrientation( 1 ); + break; + + case 0: // horizontal text + case 2: // invert horizontal text + default: + break; + } + + MIRROR( m_Pos.y, aXaxis_position ); +} + + +void SCH_TEXT::Rotate( wxPoint aPosition ) +{ + int dy; + + RotatePoint( &m_Pos, aPosition, 900 ); + SetOrientation( (GetOrientation() + 1) % 4 ); + + switch( GetOrientation() ) + { + case 0: // horizontal text + dy = m_Size.y; + break; + + case 1: // Vert Orientation UP + dy = 0; + break; + + case 2: // invert horizontal text + dy = m_Size.y; + break; + + case 3: // Vert Orientation BOTTOM + dy = 0; + break; + + default: + dy = 0; + break; + } + + m_Pos.y += dy; +} + + +void SCH_TEXT::SetOrientation( int aOrientation ) +{ + m_schematicOrientation = aOrientation; + + switch( m_schematicOrientation ) + { + default: + case 0: /* Horiz Normal Orientation (left justified) */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + break; + + case 1: /* Vert Orientation UP */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + break; + + case 2: /* Horiz Orientation - Right justified */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + break; + + case 3: /* Vert Orientation BOTTOM */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_BOTTOM; + break; + } +} + + +void SCH_TEXT::SwapData( SCH_ITEM* aItem ) +{ + SCH_TEXT* item = (SCH_TEXT*) aItem; + + std::swap( m_Text, item->m_Text ); + std::swap( m_Pos, item->m_Pos ); + std::swap( m_Size, item->m_Size ); + std::swap( m_Thickness, item->m_Thickness ); + std::swap( m_shape, item->m_shape ); + std::swap( m_Orient, item->m_Orient ); + + std::swap( m_Layer, item->m_Layer ); + std::swap( m_HJustify, item->m_HJustify ); + std::swap( m_VJustify, item->m_VJustify ); + std::swap( m_isDangling, item->m_isDangling ); + std::swap( m_schematicOrientation, item->m_schematicOrientation ); +} + + +int SCH_TEXT::GetPenSize() const +{ + int pensize = m_Thickness; + + if( pensize == 0 ) // Use default values for pen size + { + if( m_Bold ) + pensize = GetPenSizeForBold( m_Size.x ); + else + pensize = GetDefaultLineThickness(); + } + + // Clip pen size for small texts: + pensize = Clamp_Text_PenSize( pensize, m_Size, m_Bold ); + return pensize; +} + + +void SCH_TEXT::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& aOffset, + GR_DRAWMODE DrawMode, EDA_COLOR_T Color ) +{ + EDA_COLOR_T color; + int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; + EDA_RECT* clipbox = panel? panel->GetClipBox() : NULL; + + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + if( Color >= 0 ) + color = Color; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( DC, DrawMode ); + + wxPoint text_offset = aOffset + GetSchematicTextOffset(); + std::swap( linewidth, m_Thickness ); // Set the minimum width + EDA_TEXT::Draw( clipbox, DC, text_offset, color, DrawMode, FILLED, UNSPECIFIED_COLOR ); + std::swap( linewidth, m_Thickness ); // set initial value + + if( m_isDangling && panel) + DrawDanglingSymbol( panel, DC, m_Pos + aOffset, color ); + + // Enable these line to draw the bounding box (debug tests purposes only) +#if 0 + { + EDA_RECT BoundaryBox = GetBoundingBox(); + GRRect( clipbox, DC, BoundaryBox, 0, BROWN ); + } +#endif +} + + +bool SCH_TEXT::Save( FILE* aFile ) const +{ + bool success = true; + const char* shape = "~"; + + if( m_Italic ) + shape = "Italic"; + + // For compatibility reason, the text must be saved in only one text line + // so we replace all E.O.L. by \\n + wxString text = m_Text; + + text.Replace( wxT("\n"), wxT( "\\n" ) ); + + // Here we should have no CR or LF character in line + // This is not always the case if a multiline text was copied (using a copy/paste function) + // from a text that uses E.O.L characters that differs from the current EOL format + // This is mainly the case under Linux using LF symbol when copying a text from + // Windows (using CRLF symbol) + // So we must just remove the extra CR left (or LF left under MacOSX) + for( unsigned ii = 0; ii < text.Len(); ) + { + if( text[ii] == 0x0A || text[ii] == 0x0D ) + text.erase( ii, 1 ); + else + ii++; + } + + + if( fprintf( aFile, "Text Notes %-4d %-4d %-4d %-4d %s %d\n%s\n", + m_Pos.x, m_Pos.y, m_schematicOrientation, m_Size.x, + shape, m_Thickness, TO_UTF8( text ) ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_TEXT::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char Name1[256]; + char Name2[256]; + char Name3[256]; + int thickness = 0, size = 0, orient = 0; + + Name1[0] = 0; Name2[0] = 0; Name3[0] = 0; + + char* sline = (char*) aLine; + + while( ( *sline != ' ' ) && *sline ) + sline++; + + // sline points the start of parameters + int ii = sscanf( sline, "%255s %d %d %d %d %255s %255s %d", Name1, &m_Pos.x, &m_Pos.y, + &orient, &size, Name2, Name3, &thickness ); + + if( ii < 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file text load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( !aLine.ReadLine() ) + { + aErrorMsg.Printf( wxT( "Eeschema file text load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( size == 0 ) + size = GetDefaultTextSize(); + + char* text = strtok( (char*) aLine, "\n\r" ); + + if( text == NULL ) + { + aErrorMsg.Printf( wxT( "Eeschema file text load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + wxString val = FROM_UTF8( text ); + + for( ; ; ) + { + int i = val.find( wxT( "\\n" ) ); + + if( i == wxNOT_FOUND ) + break; + + val.erase( i, 2 ); + val.insert( i, wxT( "\n" ) ); + } + + m_Text = val; + m_Size.x = m_Size.y = size; + SetOrientation( orient ); + + if( isdigit( Name3[0] ) ) + { + thickness = atol( Name3 ); + m_Bold = ( thickness != 0 ); + m_Thickness = m_Bold ? GetPenSizeForBold( size ) : 0; + } + + if( strnicmp( Name2, "Italic", 6 ) == 0 ) + m_Italic = 1; + + return true; +} + + +void SCH_TEXT::GetEndPoints( std::vector & aItemList ) +{ + // Normal text labels cannot be tested for dangling ends. + if( Type() == SCH_TEXT_T ) + return; + + DANGLING_END_ITEM item( LABEL_END, this, m_Pos ); + aItemList.push_back( item ); +} + + +bool SCH_TEXT::IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ) +{ + // Normal text labels cannot be tested for dangling ends. + if( Type() == SCH_TEXT_T ) + return false; + + bool previousState = m_isDangling; + m_isDangling = true; + + for( unsigned ii = 0; ii < aItemList.size(); ii++ ) + { + DANGLING_END_ITEM& item = aItemList[ii]; + + if( item.GetItem() == this ) + continue; + + switch( item.GetType() ) + { + case PIN_END: + case LABEL_END: + case SHEET_LABEL_END: + if( m_Pos == item.GetPosition() ) + m_isDangling = false; + + break; + + case WIRE_START_END: + case BUS_START_END: + { + // These schematic items have created 2 DANGLING_END_ITEM one per end. But being + // a paranoid programmer, I'll check just in case. + ii++; + + wxCHECK_MSG( ii < aItemList.size(), previousState != m_isDangling, + wxT( "Dangling end type list overflow. Bad programmer!" ) ); + + DANGLING_END_ITEM & nextItem = aItemList[ii]; + m_isDangling = !IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_Pos ); + } + break; + + default: + break; + } + + if( !m_isDangling ) + break; + } + + return previousState != m_isDangling; +} + + +bool SCH_TEXT::IsSelectStateChanged( const wxRect& aRect ) +{ + bool previousState = IsSelected(); + + if( aRect.Contains( m_Pos ) ) + SetFlags( SELECTED ); + else + ClearFlags( SELECTED ); + + return previousState != IsSelected(); +} + + +void SCH_TEXT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const +{ + // Normal text labels do not have connection points. All others do. + if( Type() == SCH_TEXT_T ) + return; + + aPoints.push_back( m_Pos ); +} + + +const EDA_RECT SCH_TEXT::GetBoundingBox() const +{ + // We must pass the effective text thickness to GetTextBox + // when calculating the bounding box + int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; + + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + EDA_RECT rect = GetTextBox( -1, linewidth ); + + if( m_Orient ) // Rotate rect + { + wxPoint pos = rect.GetOrigin(); + wxPoint end = rect.GetEnd(); + RotatePoint( &pos, m_Pos, m_Orient ); + RotatePoint( &end, m_Pos, m_Orient ); + rect.SetOrigin( pos ); + rect.SetEnd( end ); + } + + rect.Normalize(); + return rect; +} + + +wxString SCH_TEXT::GetSelectMenuText() const +{ + wxString msg; + msg.Printf( _( "Graphic Text %s" ), GetChars( ShortenedShownText() ) ); + return msg; +} + + +void SCH_TEXT::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ) +{ + if( GetLayer() == LAYER_NOTES || GetLayer() == LAYER_SHEETLABEL ) + return; + + NETLIST_OBJECT* item = new NETLIST_OBJECT(); + item->m_SheetPath = *aSheetPath; + item->m_SheetPathInclude = *aSheetPath; + item->m_Comp = (SCH_ITEM*) this; + item->m_Type = NET_LABEL; + + if( GetLayer() == LAYER_GLOBLABEL ) + item->m_Type = NET_GLOBLABEL; + else if( GetLayer() == LAYER_HIERLABEL ) + item->m_Type = NET_HIERLABEL; + + item->m_Label = m_Text; + item->m_Start = item->m_End = m_Pos; + + aNetListItems.push_back( item ); + + /* If a bus connects to label */ + if( IsBusLabel( m_Text ) ) + item->ConvertBusToNetListItems( aNetListItems ); +} + + +bool SCH_TEXT::HitTest( const wxPoint& aPosition, int aAccuracy ) const +{ + EDA_RECT bBox = GetBoundingBox(); + bBox.Inflate( aAccuracy ); + return bBox.Contains( aPosition ); +} + + +bool SCH_TEXT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT bBox = GetBoundingBox(); + bBox.Inflate( aAccuracy ); + + if( aContained ) + return aRect.Contains( bBox ); + + return aRect.Intersects( bBox ); +} + + +void SCH_TEXT::Plot( PLOTTER* aPlotter ) +{ + static std::vector Poly; + + EDA_COLOR_T color = GetLayerColor( GetLayer() ); + wxPoint textpos = m_Pos + GetSchematicTextOffset(); + int thickness = GetPenSize(); + + aPlotter->SetCurrentLineWidth( thickness ); + + if( m_MultilineAllowed ) + { + std::vector positions; + wxArrayString strings_list; + wxStringSplit( GetShownText(), strings_list, '\n' ); + positions.reserve( strings_list.Count() ); + + GetPositionsOfLinesOfMultilineText(positions, strings_list.Count() ); + + for( unsigned ii = 0; ii < strings_list.Count(); ii++ ) + { + wxString& txt = strings_list.Item( ii ); + aPlotter->Text( positions[ii], color, txt, m_Orient, m_Size, m_HJustify, + m_VJustify, thickness, m_Italic, m_Bold ); + } + } + else + { + aPlotter->Text( textpos, color, GetShownText(), m_Orient, m_Size, m_HJustify, + m_VJustify, thickness, m_Italic, m_Bold ); + } + + /* Draw graphic symbol for global or hierarchical labels */ + CreateGraphicShape( Poly, m_Pos ); + + aPlotter->SetCurrentLineWidth( GetPenSize() ); + + if( Poly.size() ) + aPlotter->PlotPoly( Poly, NO_FILL ); +} + + +/* + * Display the type, shape, size and some other props to the Message panel + */ +void SCH_TEXT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) +{ + wxString msg; + + switch( Type() ) + { + case SCH_TEXT_T: + msg = _( "Graphic Text" ); + break; + + case SCH_LABEL_T: + msg = _( "Label" ); + break; + + case SCH_GLOBAL_LABEL_T: + msg = _( "Global Label" ); + break; + + case SCH_HIERARCHICAL_LABEL_T: + msg = _( "Hierarchical Label" ); + break; + + case SCH_SHEET_PIN_T: + msg = _( "Hierarchical Sheet Pin" ); + break; + + default: + return; + } + + aList.push_back( MSG_PANEL_ITEM( msg, GetShownText(), DARKCYAN ) ); + + switch( GetOrientation() ) + { + case 0: // horizontal text + msg = _( "Horizontal" ); + break; + + case 1: // Vert Orientation UP + msg = _( "Vertical up" ); + break; + + case 2: // invert horizontal text + msg = _( "Horizontal invert" ); + break; + + case 3: // Vert Orientation Down + msg = _( "Vertical down" ); + break; + + default: + msg = wxT( "???" ); + break; + } + + aList.push_back( MSG_PANEL_ITEM( _( "Orientation" ), msg, BROWN ) ); + + wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) }; + int style = 0; + + if( m_Italic ) + style = 1; + + if( m_Bold ) + style += 2; + + aList.push_back( MSG_PANEL_ITEM( _( "Style" ), textStyle[style], BROWN ) ); + + + // Display electricat type if it is relevant + if( (Type() == SCH_GLOBAL_LABEL_T) || + (Type() == SCH_HIERARCHICAL_LABEL_T ) || + (Type() == SCH_SHEET_PIN_T ) ) + { + switch( GetShape() ) + { + case NET_INPUT: msg = _( "Input" ); break; + case NET_OUTPUT: msg = _( "Output" ); break; + case NET_BIDI: msg = _( "Bidirectional" ); break; + case NET_TRISTATE: msg = _( "Tri-State" ); break; + case NET_UNSPECIFIED: msg = _( "Passive" ); break; + default: msg = wxT( "???" ); break; + } + + aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, BLUE ) ); + } + + // Display text size (X or Y value, with are the same value in Eeschema) + msg = StringFromValue( g_UserUnit, m_Size.x, true ); + aList.push_back( MSG_PANEL_ITEM( _( "Size" ), msg, RED ) ); +} + +#if defined(DEBUG) + +void SCH_TEXT::Show( int nestLevel, std::ostream& os ) const +{ + // XML output: + wxString s = GetClass(); + + NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() + << " layer=\"" << m_Layer << '"' + << " shape=\"" << m_shape << '"' + << " dangling=\"" << m_isDangling << '"' + << '>' + << TO_UTF8( m_Text ) + << "\n"; +} + +#endif + + +SCH_LABEL::SCH_LABEL( const wxPoint& pos, const wxString& text ) : + SCH_TEXT( pos, text, SCH_LABEL_T ) +{ + m_Layer = LAYER_LOCLABEL; + m_shape = NET_INPUT; + m_isDangling = true; + m_MultilineAllowed = false; +} + + +EDA_ITEM* SCH_LABEL::Clone() const +{ + return new SCH_LABEL( *this ); +} + + +wxPoint SCH_LABEL::GetSchematicTextOffset() const +{ + return SCH_TEXT::GetSchematicTextOffset(); +} + + +void SCH_LABEL::SetOrientation( int aOrientation ) +{ + SCH_TEXT::SetOrientation( aOrientation ); +} + + +void SCH_LABEL::MirrorX( int aXaxis_position ) +{ + // Text is NOT really mirrored; it is moved to a suitable position + switch( GetOrientation() ) + { + case 1: // Vert Orientation UP + SetOrientation( 3 ); + break; + + case 3: // Vert Orientation BOTTOM + SetOrientation( 1 ); + break; + + case 0: // horizontal text + case 2: // invert horizontal text + default: + break; + } + + MIRROR( m_Pos.y, aXaxis_position ); +} + + +void SCH_LABEL::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); + SetOrientation( (GetOrientation() + 1) % 4 ); +} + + +bool SCH_LABEL::Save( FILE* aFile ) const +{ + bool success = true; + const char* shape = "~"; + + if( m_Italic ) + shape = "Italic"; + + if( fprintf( aFile, "Text Label %-4d %-4d %-4d %-4d %s %d\n%s\n", + m_Pos.x, m_Pos.y, m_schematicOrientation, m_Size.x, shape, + m_Thickness, TO_UTF8( m_Text ) ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_LABEL::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char Name1[256]; + char Name2[256]; + char Name3[256]; + int thickness = 0, size = 0, orient = 0; + + Name1[0] = 0; Name2[0] = 0; Name3[0] = 0; + + char* sline = (char*) aLine; + + while( ( *sline != ' ' ) && *sline ) + sline++; + + // sline points the start of parameters + int ii = sscanf( sline, "%255s %d %d %d %d %255s %255s %d", Name1, &m_Pos.x, &m_Pos.y, + &orient, &size, Name2, Name3, &thickness ); + + if( ii < 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( !aLine.ReadLine() ) + { + aErrorMsg.Printf( wxT( "Eeschema file label load error atline %d" ), + aLine.LineNumber() ); + return false; + } + + if( size == 0 ) + size = GetDefaultTextSize(); + + char* text = strtok( (char*) aLine, "\n\r" ); + + if( text == NULL ) + { + aErrorMsg.Printf( wxT( "Eeschema file label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + m_Text = FROM_UTF8( text ); + m_Size.x = m_Size.y = size; + SetOrientation( orient ); + + if( isdigit( Name3[0] ) ) + { + thickness = atol( Name3 ); + m_Bold = ( thickness != 0 ); + m_Thickness = m_Bold ? GetPenSizeForBold( size ) : 0; + } + + if( stricmp( Name2, "Italic" ) == 0 ) + m_Italic = 1; + + return true; +} + + +void SCH_LABEL::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE DrawMode, EDA_COLOR_T Color ) +{ + SCH_TEXT::Draw( panel, DC, offset, DrawMode, Color ); +} + + +const EDA_RECT SCH_LABEL::GetBoundingBox() const +{ + int x, y, dx, dy, length, height; + + x = m_Pos.x; + y = m_Pos.y; + int width = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + length = LenSize( GetShownText() ); + height = m_Size.y + width; + dx = dy = 0; + + switch( m_schematicOrientation ) + { + case 0: /* Horiz Normal Orientation (left justified) */ + dx = 2 * DANGLING_SYMBOL_SIZE + length; + dy = -2 * DANGLING_SYMBOL_SIZE - height - TXTMARGE; + x -= DANGLING_SYMBOL_SIZE; + y += DANGLING_SYMBOL_SIZE; + break; + + case 1: /* Vert Orientation UP */ + dx = -2 * DANGLING_SYMBOL_SIZE - height - TXTMARGE; + dy = -2 * DANGLING_SYMBOL_SIZE - length; + x += DANGLING_SYMBOL_SIZE; + y += DANGLING_SYMBOL_SIZE; + break; + + case 2: /* Horiz Orientation - Right justified */ + dx = -2 * DANGLING_SYMBOL_SIZE - length; + dy = -2 * DANGLING_SYMBOL_SIZE - height - TXTMARGE; + x += DANGLING_SYMBOL_SIZE; + y += DANGLING_SYMBOL_SIZE; + break; + + case 3: /* Vert Orientation BOTTOM */ + dx = -2 * DANGLING_SYMBOL_SIZE - height - TXTMARGE; + dy = 2 * DANGLING_SYMBOL_SIZE + length; + x += DANGLING_SYMBOL_SIZE; + y -= DANGLING_SYMBOL_SIZE; + break; + } + + EDA_RECT box( wxPoint( x, y ), wxSize( dx, dy ) ); + box.Normalize(); + return box; +} + + +wxString SCH_LABEL::GetSelectMenuText() const +{ + wxString msg; + msg.Printf( _( "Label %s" ), GetChars( ShortenedShownText() ) ); + return msg; +} + + + +SCH_GLOBALLABEL::SCH_GLOBALLABEL( const wxPoint& pos, const wxString& text ) : + SCH_TEXT( pos, text, SCH_GLOBAL_LABEL_T ) +{ + m_Layer = LAYER_GLOBLABEL; + m_shape = NET_BIDI; + m_isDangling = true; + m_MultilineAllowed = false; +} + + +EDA_ITEM* SCH_GLOBALLABEL::Clone() const +{ + return new SCH_GLOBALLABEL( *this ); +} + + +bool SCH_GLOBALLABEL::Save( FILE* aFile ) const +{ + bool success = true; + const char* shape = "~"; + + if( m_Italic ) + shape = "Italic"; + + if( fprintf( aFile, "Text GLabel %-4d %-4d %-4d %-4d %s %s %d\n%s\n", + m_Pos.x, m_Pos.y, m_schematicOrientation, m_Size.x, + SheetLabelType[m_shape], shape, m_Thickness, TO_UTF8( m_Text ) ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_GLOBALLABEL::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char Name1[256]; + char Name2[256]; + char Name3[256]; + int thickness = 0, size = 0, orient = 0; + + Name1[0] = 0; Name2[0] = 0; Name3[0] = 0; + + char* sline = (char*) aLine; + + while( (*sline != ' ' ) && *sline ) + sline++; + + // sline points the start of parameters + int ii = sscanf( sline, "%255s %d %d %d %d %255s %255s %d", Name1, &m_Pos.x, &m_Pos.y, + &orient, &size, Name2, Name3, &thickness ); + + if( ii < 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file global label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( !aLine.ReadLine() ) + { + aErrorMsg.Printf( wxT( "Eeschema file global label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( size == 0 ) + size = GetDefaultTextSize(); + + char* text = strtok( (char*) aLine, "\n\r" ); + + if( text == NULL ) + { + aErrorMsg.Printf( wxT( "Eeschema file global label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + m_Text = FROM_UTF8( text ); + m_Size.x = m_Size.y = size; + SetOrientation( orient ); + m_shape = NET_INPUT; + m_Bold = ( thickness != 0 ); + m_Thickness = m_Bold ? GetPenSizeForBold( size ) : 0; + + if( stricmp( Name2, SheetLabelType[NET_OUTPUT] ) == 0 ) + m_shape = NET_OUTPUT; + + if( stricmp( Name2, SheetLabelType[NET_BIDI] ) == 0 ) + m_shape = NET_BIDI; + + if( stricmp( Name2, SheetLabelType[NET_TRISTATE] ) == 0 ) + m_shape = NET_TRISTATE; + + if( stricmp( Name2, SheetLabelType[NET_UNSPECIFIED] ) == 0 ) + m_shape = NET_UNSPECIFIED; + + if( stricmp( Name3, "Italic" ) == 0 ) + m_Italic = 1; + + return true; +} + + +void SCH_GLOBALLABEL::MirrorY( int aYaxis_position ) +{ + /* The global label is NOT really mirrored. + * for an horizontal label, the schematic orientation is changed. + * for a vertical label, the schematic orientation is not changed. + * and the label is moved to a suitable position + */ + switch( GetOrientation() ) + { + case 0: /* horizontal text */ + SetOrientation( 2 ); + break; + + case 2: /* invert horizontal text*/ + SetOrientation( 0 ); + break; + } + + MIRROR( m_Pos.x, aYaxis_position ); +} + + +void SCH_GLOBALLABEL::MirrorX( int aXaxis_position ) +{ + switch( GetOrientation() ) + { + case 1: /* vertical text */ + SetOrientation( 3 ); + break; + + case 3: /* invert vertical text*/ + SetOrientation( 1 ); + break; + } + + MIRROR( m_Pos.y, aXaxis_position ); +} + + +void SCH_GLOBALLABEL::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); + SetOrientation( (GetOrientation() + 3) % 4 ); +} + + +wxPoint SCH_GLOBALLABEL::GetSchematicTextOffset() const +{ + wxPoint text_offset; + int width = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + + width = Clamp_Text_PenSize( width, m_Size, m_Bold ); + int HalfSize = m_Size.x / 2; + int offset = width; + + switch( m_shape ) + { + case NET_INPUT: + case NET_BIDI: + case NET_TRISTATE: + offset += HalfSize; + break; + + case NET_OUTPUT: + case NET_UNSPECIFIED: + offset += TXTMARGE; + break; + + default: + break; + } + + switch( m_schematicOrientation ) + { + case 0: /* Orientation horiz normal */ + text_offset.x -= offset; + break; + + case 1: /* Orientation vert UP */ + text_offset.y -= offset; + break; + + case 2: /* Orientation horiz inverse */ + text_offset.x += offset; + break; + + case 3: /* Orientation vert BOTTOM */ + text_offset.y += offset; + break; + } + + return text_offset; +} + + +void SCH_GLOBALLABEL::SetOrientation( int aOrientation ) +{ + m_schematicOrientation = aOrientation; + + switch( m_schematicOrientation ) + { + default: + case 0: /* Horiz Normal Orientation */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 1: /* Vert Orientation UP */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 2: /* Horiz Orientation */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 3: /* Vert Orientation BOTTOM */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + } +} + + +void SCH_GLOBALLABEL::Draw( EDA_DRAW_PANEL* panel, + wxDC* DC, + const wxPoint& aOffset, + GR_DRAWMODE DrawMode, + EDA_COLOR_T Color ) +{ + static std::vector Poly; + EDA_COLOR_T color; + wxPoint text_offset = aOffset + GetSchematicTextOffset(); + + if( Color >= 0 ) + color = Color; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( DC, DrawMode ); + + int linewidth = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + std::swap( linewidth, m_Thickness ); // Set the minimum width + EDA_RECT* clipbox = panel? panel->GetClipBox() : NULL; + EDA_TEXT::Draw( clipbox, DC, text_offset, color, DrawMode, FILLED, UNSPECIFIED_COLOR ); + std::swap( linewidth, m_Thickness ); // set initial value + + CreateGraphicShape( Poly, m_Pos + aOffset ); + GRPoly( clipbox, DC, Poly.size(), &Poly[0], 0, linewidth, color, color ); + + if( m_isDangling && panel ) + DrawDanglingSymbol( panel, DC, m_Pos + aOffset, color ); + + // Enable these line to draw the bounding box (debug tests purposes only) +#if 0 + { + EDA_RECT BoundaryBox = GetBoundingBox(); + GRRect( clipbox, DC, BoundaryBox, 0, BROWN ); + } +#endif +} + + +void SCH_GLOBALLABEL::CreateGraphicShape( std::vector & aPoints, const wxPoint& Pos ) +{ + int HalfSize = m_Size.y / 2; + int linewidth = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + aPoints.clear(); + + int symb_len = LenSize( GetShownText() ) + ( TXTMARGE * 2 ); + + // Create outline shape : 6 points + int x = symb_len + linewidth + 3; + + // Use negation bar Y position to calculate full vertical size + #define Y_CORRECTION 1.3 + // Note: this factor is due to the fact the negation bar Y position + // does not give exactly the full Y size of text + // and is experimentally set to this value + int y = KiROUND( OverbarPositionY( HalfSize ) * Y_CORRECTION ); + // add room for line thickness and space between top of text and graphic shape + y += linewidth; + + // Starting point(anchor) + aPoints.push_back( wxPoint( 0, 0 ) ); + aPoints.push_back( wxPoint( 0, -y ) ); // Up + aPoints.push_back( wxPoint( -x, -y ) ); // left + aPoints.push_back( wxPoint( -x, 0 ) ); // Up left + aPoints.push_back( wxPoint( -x, y ) ); // left down + aPoints.push_back( wxPoint( 0, y ) ); // down + + int x_offset = 0; + + switch( m_shape ) + { + case NET_INPUT: + x_offset = -HalfSize; + aPoints[0].x += HalfSize; + break; + + case NET_OUTPUT: + aPoints[3].x -= HalfSize; + break; + + case NET_BIDI: + case NET_TRISTATE: + x_offset = -HalfSize; + aPoints[0].x += HalfSize; + aPoints[3].x -= HalfSize; + break; + + case NET_UNSPECIFIED: + default: + break; + } + + int angle = 0; + + switch( m_schematicOrientation ) + { + case 0: /* Orientation horiz normal */ + break; + + case 1: /* Orientation vert UP */ + angle = -900; + break; + + case 2: /* Orientation horiz inverse */ + angle = 1800; + break; + + case 3: /* Orientation vert BOTTOM */ + angle = 900; + break; + } + + // Rotate outlines and move corners in real position + for( unsigned ii = 0; ii < aPoints.size(); ii++ ) + { + aPoints[ii].x += x_offset; + + if( angle ) + RotatePoint( &aPoints[ii], angle ); + + aPoints[ii] += Pos; + } + + aPoints.push_back( aPoints[0] ); // closing +} + + +const EDA_RECT SCH_GLOBALLABEL::GetBoundingBox() const +{ + int x, y, dx, dy, length, height; + + x = m_Pos.x; + y = m_Pos.y; + dx = dy = 0; + + int width = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + height = ( (m_Size.y * 15) / 10 ) + width + 2 * TXTMARGE; + + // text X size add height for triangular shapes(bidirectional) + length = LenSize( GetShownText() ) + height + DANGLING_SYMBOL_SIZE; + + switch( m_schematicOrientation ) // respect orientation + { + case 0: /* Horiz Normal Orientation (left justified) */ + dx = -length; + dy = height; + x += DANGLING_SYMBOL_SIZE; + y -= height / 2; + break; + + case 1: /* Vert Orientation UP */ + dx = height; + dy = -length; + x -= height / 2; + y += DANGLING_SYMBOL_SIZE; + break; + + case 2: /* Horiz Orientation - Right justified */ + dx = length; + dy = height; + x -= DANGLING_SYMBOL_SIZE; + y -= height / 2; + break; + + case 3: /* Vert Orientation BOTTOM */ + dx = height; + dy = length; + x -= height / 2; + y -= DANGLING_SYMBOL_SIZE; + break; + } + + EDA_RECT box( wxPoint( x, y ), wxSize( dx, dy ) ); + box.Normalize(); + return box; +} + + +wxString SCH_GLOBALLABEL::GetSelectMenuText() const +{ + wxString msg; + msg.Printf( _( "Global Label %s" ), GetChars( ShortenedShownText() ) ); + return msg; +} + + + +SCH_HIERLABEL::SCH_HIERLABEL( const wxPoint& pos, const wxString& text, KICAD_T aType ) : + SCH_TEXT( pos, text, aType ) +{ + m_Layer = LAYER_HIERLABEL; + m_shape = NET_INPUT; + m_isDangling = true; + m_MultilineAllowed = false; +} + + +EDA_ITEM* SCH_HIERLABEL::Clone() const +{ + return new SCH_HIERLABEL( *this ); +} + + +bool SCH_HIERLABEL::Save( FILE* aFile ) const +{ + bool success = true; + const char* shape = "~"; + + if( m_Italic ) + shape = "Italic"; + + if( fprintf( aFile, "Text HLabel %-4d %-4d %-4d %-4d %s %s %d\n%s\n", + m_Pos.x, m_Pos.y, m_schematicOrientation, m_Size.x, + SheetLabelType[m_shape], shape, m_Thickness, TO_UTF8( m_Text ) ) == EOF ) + { + success = false; + } + + return success; +} + + +bool SCH_HIERLABEL::Load( LINE_READER& aLine, wxString& aErrorMsg ) +{ + char Name1[256]; + char Name2[256]; + char Name3[256]; + int thickness = 0, size = 0, orient = 0; + + Name1[0] = 0; Name2[0] = 0; Name3[0] = 0; + + char* sline = (char*) aLine; + + while( (*sline != ' ' ) && *sline ) + sline++; + + // sline points the start of parameters + int ii = sscanf( sline, "%255s %d %d %d %d %255s %255s %d", Name1, &m_Pos.x, &m_Pos.y, + &orient, &size, Name2, Name3, &thickness ); + + if( ii < 4 ) + { + aErrorMsg.Printf( wxT( "Eeschema file hierarchical label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( !aLine.ReadLine() ) + { + aErrorMsg.Printf( wxT( "Eeschema file hierarchical label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + if( size == 0 ) + size = GetDefaultTextSize(); + + char* text = strtok( (char*) aLine, "\n\r" ); + + if( text == NULL ) + { + aErrorMsg.Printf( wxT( "Eeschema file hierarchical label load error at line %d" ), + aLine.LineNumber() ); + return false; + } + + m_Text = FROM_UTF8( text ); + m_Size.x = m_Size.y = size; + SetOrientation( orient ); + m_shape = NET_INPUT; + m_Bold = ( thickness != 0 ); + m_Thickness = m_Bold ? GetPenSizeForBold( size ) : 0; + + if( stricmp( Name2, SheetLabelType[NET_OUTPUT] ) == 0 ) + m_shape = NET_OUTPUT; + + if( stricmp( Name2, SheetLabelType[NET_BIDI] ) == 0 ) + m_shape = NET_BIDI; + + if( stricmp( Name2, SheetLabelType[NET_TRISTATE] ) == 0 ) + m_shape = NET_TRISTATE; + + if( stricmp( Name2, SheetLabelType[NET_UNSPECIFIED] ) == 0 ) + m_shape = NET_UNSPECIFIED; + + if( stricmp( Name3, "Italic" ) == 0 ) + m_Italic = 1; + + return true; +} + + +void SCH_HIERLABEL::SetOrientation( int aOrientation ) +{ + m_schematicOrientation = aOrientation; + + switch( m_schematicOrientation ) + { + default: + case 0: /* Horiz Normal Orientation */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 1: /* Vert Orientation UP */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 2: /* Horiz Orientation */ + m_Orient = TEXT_ORIENT_HORIZ; + m_HJustify = GR_TEXT_HJUSTIFY_LEFT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + + case 3: /* Vert Orientation BOTTOM */ + m_Orient = TEXT_ORIENT_VERT; + m_HJustify = GR_TEXT_HJUSTIFY_RIGHT; + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; + break; + } +} + + +void SCH_HIERLABEL::Draw( EDA_DRAW_PANEL* panel, + wxDC* DC, + const wxPoint& offset, + GR_DRAWMODE DrawMode, + EDA_COLOR_T Color ) +{ + static std::vector Poly; + EDA_COLOR_T color; + int linewidth = m_Thickness == 0 ? + GetDefaultLineThickness() : m_Thickness; + EDA_RECT* clipbox = panel? panel->GetClipBox() : NULL; + + linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); + + if( Color >= 0 ) + color = Color; + else + color = GetLayerColor( m_Layer ); + + GRSetDrawMode( DC, DrawMode ); + + std::swap( linewidth, m_Thickness ); // Set the minimum width + wxPoint text_offset = offset + GetSchematicTextOffset(); + EDA_TEXT::Draw( clipbox, DC, text_offset, color, DrawMode, FILLED, UNSPECIFIED_COLOR ); + std::swap( linewidth, m_Thickness ); // set initial value + + CreateGraphicShape( Poly, m_Pos + offset ); + GRPoly( clipbox, DC, Poly.size(), &Poly[0], 0, linewidth, color, color ); + + if( m_isDangling && panel ) + DrawDanglingSymbol( panel, DC, m_Pos + offset, color ); + + // Enable these line to draw the bounding box (debug tests purposes only) +#if 0 + { + EDA_RECT BoundaryBox = GetBoundingBox(); + GRRect( clipbox, DC, BoundaryBox, 0, BROWN ); + } +#endif +} + + +void SCH_HIERLABEL::CreateGraphicShape( std::vector & aPoints, const wxPoint& Pos ) +{ + int* Template = TemplateShape[m_shape][m_schematicOrientation]; + int HalfSize = m_Size.x / 2; + + int imax = *Template; Template++; + + aPoints.clear(); + + for( int ii = 0; ii < imax; ii++ ) + { + wxPoint corner; + corner.x = ( HalfSize * (*Template) ) + Pos.x; + Template++; + + corner.y = ( HalfSize * (*Template) ) + Pos.y; + Template++; + + aPoints.push_back( corner ); + } +} + + +const EDA_RECT SCH_HIERLABEL::GetBoundingBox() const +{ + int x, y, dx, dy, length, height; + + x = m_Pos.x; + y = m_Pos.y; + dx = dy = 0; + + int width = (m_Thickness == 0) ? GetDefaultLineThickness() : m_Thickness; + height = m_Size.y + width + 2 * TXTMARGE; + length = LenSize( GetShownText() ) + + height // add height for triangular shapes + + 2 * DANGLING_SYMBOL_SIZE; + + switch( m_schematicOrientation ) // respect orientation + { + case 0: /* Horiz Normal Orientation (left justified) */ + dx = -length; + dy = height; + x += DANGLING_SYMBOL_SIZE; + y -= height / 2; + break; + + case 1: /* Vert Orientation UP */ + dx = height; + dy = -length; + x -= height / 2; + y += DANGLING_SYMBOL_SIZE; + break; + + case 2: /* Horiz Orientation - Right justified */ + dx = length; + dy = height; + x -= DANGLING_SYMBOL_SIZE; + y -= height / 2; + break; + + case 3: /* Vert Orientation BOTTOM */ + dx = height; + dy = length; + x -= height / 2; + y -= DANGLING_SYMBOL_SIZE; + break; + } + + EDA_RECT box( wxPoint( x, y ), wxSize( dx, dy ) ); + box.Normalize(); + return box; +} + + +wxPoint SCH_HIERLABEL::GetSchematicTextOffset() const +{ + wxPoint text_offset; + + int width = std::max( m_Thickness, GetDefaultLineThickness() ); + + int ii = m_Size.x + TXTMARGE + width; + + switch( m_schematicOrientation ) + { + case 0: /* Orientation horiz normale */ + text_offset.x = -ii; + break; + + case 1: /* Orientation vert UP */ + text_offset.y = -ii; + break; + + case 2: /* Orientation horiz inverse */ + text_offset.x = ii; + break; + + case 3: /* Orientation vert BOTTOM */ + text_offset.y = ii; + break; + } + + return text_offset; +} + + +void SCH_HIERLABEL::MirrorY( int aYaxis_position ) +{ + /* The hierarchical label is NOT really mirrored for an horizontal label, the schematic + * orientation is changed. For a vertical label, the schematic orientation is not changed + * and the label is moved to a suitable position. + */ + + switch( GetOrientation() ) + { + case 0: /* horizontal text */ + SetOrientation( 2 ); + break; + + case 2: /* invert horizontal text*/ + SetOrientation( 0 ); + break; + } + + MIRROR( m_Pos.x, aYaxis_position ); +} + + +void SCH_HIERLABEL::MirrorX( int aXaxis_position ) +{ + switch( GetOrientation() ) + { + case 1: /* vertical text */ + SetOrientation( 3 ); + break; + + case 3: /* invert vertical text*/ + SetOrientation( 1 ); + break; + } + + MIRROR( m_Pos.y, aXaxis_position ); +} + + +void SCH_HIERLABEL::Rotate( wxPoint aPosition ) +{ + RotatePoint( &m_Pos, aPosition, 900 ); + SetOrientation( (GetOrientation() + 3) % 4 ); +} + + +wxString SCH_HIERLABEL::GetSelectMenuText() const +{ + wxString msg; + msg.Printf( _( "Hierarchical Label %s" ), GetChars( ShortenedShownText() ) ); + return msg; +} diff --git a/eeschema/sch_text.h b/eeschema/sch_text.h new file mode 100644 index 00000000..a570bfc5 --- /dev/null +++ b/eeschema/sch_text.h @@ -0,0 +1,366 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sch_text.h + * @brief Definitions of the SCH_TEXT class and derivatives for Eeschema. + */ + +#ifndef CLASS_TEXT_LABEL_H +#define CLASS_TEXT_LABEL_H + + +#include +#include +#include + + +class LINE_READER; +class NETLIST_OBJECT_LIST; + + +/* Type of SCH_HIERLABEL and SCH_GLOBALLABEL + * mainly used to handle the graphic associated shape + */ +typedef enum { + NET_INPUT, + NET_OUTPUT, + NET_BIDI, + NET_TRISTATE, + NET_UNSPECIFIED, + NET_TMAX /* Last value */ +} TypeSheetLabel; + + +extern const char* SheetLabelType[]; /* names of types of labels */ + +class SCH_TEXT : public SCH_ITEM, public EDA_TEXT +{ +protected: + int m_shape; + + /// True if not connected to another object if the object derive from SCH_TEXT + /// supports connections. + bool m_isDangling; + + /** + * The orientation of text and any associated drawing elements of derived objects. + * 0 is the horizontal and left justified. + * 1 is vertical and top justified. + * 2 is horizontal and right justified. It is the equivalent of the mirrored 0 orentation. + * 3 is veritcal and bottom justifiend. It is the equivalent of the mirrored 1 orentation. + * This is a duplicattion of m_Orient, m_HJustified, and m_VJustified in #EDA_TEXT but is + * easier to handle that 3 parameters when editing and reading and saving files. + */ + int m_schematicOrientation; + +public: + SCH_TEXT( const wxPoint& pos = wxPoint( 0, 0 ), + const wxString& text = wxEmptyString, + KICAD_T aType = SCH_TEXT_T ); + + /** + * Copy Constructor + * clones \a aText into a new object. All members are copied as is except + * for the #m_isDangling member which is set to false. This prevents newly + * copied objects derived from #SCH_TEXT from having their connection state + * improperly set. + */ + SCH_TEXT( const SCH_TEXT& aText ); + + ~SCH_TEXT() { } + + virtual wxString GetClass() const + { + return wxT( "SCH_TEXT" ); + } + + /** + * Function IncrementLabel + * increments the label text, if it ends with a number. + * @param aIncrement = the increment value to add to the number + * ending the text + */ + void IncrementLabel( int aIncrement ); + + /** + * Function SetOrientation + * Set m_schematicOrientation, and initialize + * m_orient,m_HJustified and m_VJustified, according to the value of + * m_schematicOrientation (for a text ) + * must be called after changing m_schematicOrientation + * @param aSchematicOrientation = + * 0 = normal (horizontal, left justified). + * 1 = up (vertical) + * 2 = (horizontal, right justified). This can be seen as the mirrored position of 0 + * 3 = bottom . This can be seen as the mirrored position of up + */ + virtual void SetOrientation( int aSchematicOrientation ); + + int GetOrientation() { return m_schematicOrientation; } + + int GetShape() const { return m_shape; } + + void SetShape( int aShape ) { m_shape = aShape; } + + /** + * Function GetSchematicTextOffset (virtual) + * @return the offset between the SCH_TEXT position and the text itself position + * + * This offset depends on the orientation, the type of text, and the area required to + * draw the associated graphic symbol or to put the text above a wire. + */ + virtual wxPoint GetSchematicTextOffset() const; + + virtual void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE draw_mode, EDA_COLOR_T Color = UNSPECIFIED_COLOR ); + + /** + * Function CreateGraphicShape + * Calculates the graphic shape (a polygon) associated to the text + * @param aPoints A buffer to fill with polygon corners coordinates + * @param Pos Position of the shape, for texts and labels: do nothing + * Mainly for derived classes (SCH_SHEET_PIN and Hierarchical labels) + */ + virtual void CreateGraphicShape( std::vector & aPoints, const wxPoint& Pos ) + { + aPoints.clear(); + } + + virtual void SwapData( SCH_ITEM* aItem ); + + virtual const EDA_RECT GetBoundingBox() const; + + virtual bool Save( FILE* aFile ) const; + + virtual bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + virtual int GetPenSize() const; + + // Geometric transforms (used in block operations): + + virtual void Move( const wxPoint& aMoveVector ) + { + m_Pos += aMoveVector; + } + + virtual void MirrorY( int aYaxis_position ); + + virtual void MirrorX( int aXaxis_position ); + + virtual void Rotate( wxPoint aPosition ); + + virtual bool Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation ); + + virtual bool Replace( wxFindReplaceData& aSearchData, void* aAuxData = NULL ) + { + return EDA_ITEM::Replace( aSearchData, m_Text ); + } + + virtual bool IsReplaceable() const { return true; } + + virtual void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ); + + virtual bool IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ); + + virtual bool IsDangling() const { return m_isDangling; } + + virtual bool IsSelectStateChanged( const wxRect& aRect ); + + virtual void GetConnectionPoints( std::vector< wxPoint >& aPoints ) const; + + virtual bool CanIncrementLabel() const { return true; } + + virtual wxString GetSelectMenuText() const; + + virtual BITMAP_DEF GetMenuImage() const { return add_text_xpm; } + + virtual void GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems, + SCH_SHEET_PATH* aSheetPath ); + + virtual wxPoint GetPosition() const { return m_Pos; } + + virtual void SetPosition( const wxPoint& aPosition ) { m_Pos = aPosition; } + + virtual bool HitTest( const wxPoint& aPosition, int aAccuracy ) const; + + virtual bool HitTest( const EDA_RECT& aRect, bool aContained = false, + int aAccuracy = 0 ) const; + + virtual void Plot( PLOTTER* aPlotter ); + + virtual EDA_ITEM* Clone() const; + + void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + +#if defined(DEBUG) + void Show( int nestLevel, std::ostream& os ) const; // override +#endif +}; + + +class SCH_LABEL : public SCH_TEXT +{ +public: + SCH_LABEL( const wxPoint& pos = wxPoint( 0, 0 ), const wxString& text = wxEmptyString ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_LABEL() { } + + void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE draw_mode, EDA_COLOR_T Color = UNSPECIFIED_COLOR ); + + wxString GetClass() const + { + return wxT( "SCH_LABEL" ); + } + + void SetOrientation( int aSchematicOrientation ); + + wxPoint GetSchematicTextOffset() const; + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + bool IsConnectable() const { return true; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_line_label_xpm; } + + bool IsReplaceable() const { return true; } + + EDA_ITEM* Clone() const; + +private: + bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; } +}; + + +class SCH_GLOBALLABEL : public SCH_TEXT +{ +public: + SCH_GLOBALLABEL( const wxPoint& pos = wxPoint( 0, 0 ), const wxString& text = wxEmptyString ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_GLOBALLABEL() { } + + void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE draw_mode, EDA_COLOR_T Color = UNSPECIFIED_COLOR ); + + wxString GetClass() const + { + return wxT( "SCH_GLOBALLABEL" ); + } + + void SetOrientation( int aSchematicOrientation ); + + wxPoint GetSchematicTextOffset() const; + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + void CreateGraphicShape( std::vector & aPoints, const wxPoint& aPos ); + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool IsConnectable() const { return true; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_glabel_xpm; } + + EDA_ITEM* Clone() const; + +private: + bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; } +}; + + +class SCH_HIERLABEL : public SCH_TEXT +{ +public: + SCH_HIERLABEL( const wxPoint& pos = wxPoint( 0, 0 ), + const wxString& text = wxEmptyString, + KICAD_T aType = SCH_HIERARCHICAL_LABEL_T ); + + // Do not create a copy constructor. The one generated by the compiler is adequate. + + ~SCH_HIERLABEL() { } + + void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, + GR_DRAWMODE draw_mode, EDA_COLOR_T Color = UNSPECIFIED_COLOR ); + + wxString GetClass() const + { + return wxT( "SCH_HIERLABEL" ); + } + + void SetOrientation( int aSchematicOrientation ); + + wxPoint GetSchematicTextOffset() const; + + void CreateGraphicShape( std::vector & aPoints, const wxPoint& Pos ); + + bool Save( FILE* aFile ) const; + + bool Load( LINE_READER& aLine, wxString& aErrorMsg ); + + const EDA_RECT GetBoundingBox() const; // Virtual + + void MirrorY( int aYaxis_position ); + + void MirrorX( int aXaxis_position ); + + void Rotate( wxPoint aPosition ); + + bool IsConnectable() const { return true; } + + wxString GetSelectMenuText() const; + + BITMAP_DEF GetMenuImage() const { return add_hierarchical_label_xpm; } + + EDA_ITEM* Clone() const; + +private: + bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; } +}; + +#endif /* CLASS_TEXT_LABEL_H */ diff --git a/eeschema/sch_validators.cpp b/eeschema/sch_validators.cpp new file mode 100644 index 00000000..b506f274 --- /dev/null +++ b/eeschema/sch_validators.cpp @@ -0,0 +1,141 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com + * Copyright (C) 2016-2017 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_validators.cpp + * @brief Implementation of control validators for schematic dialogs. + */ + +#include +#include + +SCH_FIELD_VALIDATOR::SCH_FIELD_VALIDATOR( bool aIsCmplibEditor, + int aFieldId, wxString* aValue ) : + wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, aValue ) +{ + m_fieldId = aFieldId; + m_isLibEditor = aIsCmplibEditor; + + // Fields cannot contain carriage returns, line feeds, or tabs. + wxString excludes( "\r\n\t" ); + + // The reference field cannot contain spaces. + if( aFieldId == REFERENCE ) + excludes += " "; + else if( aFieldId == VALUE && m_isLibEditor ) + excludes += " "; + + long style = GetStyle(); + + // The reference and value fields cannot be empty. + if( aFieldId == REFERENCE || aFieldId == VALUE ) + style |= wxFILTER_EMPTY; + + SetStyle( style ); + SetCharExcludes( excludes ); +} + + +SCH_FIELD_VALIDATOR::SCH_FIELD_VALIDATOR( const SCH_FIELD_VALIDATOR& aValidator ) : + wxTextValidator( aValidator ) +{ + m_fieldId = aValidator.m_fieldId; + m_isLibEditor = aValidator.m_isLibEditor; +} + + +bool SCH_FIELD_VALIDATOR::Validate( wxWindow *aParent ) +{ + // If window is disabled, simply return + if( !m_validatorWindow->IsEnabled() ) + return true; + + wxTextEntry * const text = GetTextEntry(); + + if( !text ) + return false; + + wxString val( text->GetValue() ); + wxString tmp = val.Clone(); // For trailing and leading white space tests. + wxString fieldName; + + switch( m_fieldId ) + { + case REFERENCE: fieldName = _( "reference designator" ); break; + case VALUE: fieldName = _( "value" ); break; + case FOOTPRINT: fieldName = _( "footprint" ); break; + case DATASHEET: fieldName = _( "data sheet" ); break; + default: fieldName = _( "user defined" ); break; + }; + + wxString errorMsg; + + // We can only do some kinds of validation once the input is complete, so + // check for them here: + if( HasFlag( wxFILTER_EMPTY ) && val.empty() ) + errorMsg.Printf( _( "The %s field cannot be empty." ), fieldName ); + else if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( val ) ) + { + wxArrayString whiteSpace; + bool spaceIllegal = ( m_fieldId == REFERENCE ) || + ( m_fieldId == VALUE && m_isLibEditor ); + + if( val.Find( '\r' ) != wxNOT_FOUND ) + whiteSpace.Add( _( "carriage return" ) ); + if( val.Find( '\n' ) != wxNOT_FOUND ) + whiteSpace.Add( _( "line feed" ) ); + if( val.Find( '\t' ) != wxNOT_FOUND ) + whiteSpace.Add( _( "tab" ) ); + if( spaceIllegal && (val.Find( ' ' ) != wxNOT_FOUND) ) + whiteSpace.Add( _( "space" ) ); + + wxString badChars; + + if( whiteSpace.size() == 1 ) + badChars = whiteSpace[0]; + else if( whiteSpace.size() == 2 ) + badChars.Printf( _( "%s or %s" ), whiteSpace[0], whiteSpace[1] ); + else if( whiteSpace.size() == 3 ) + badChars.Printf( _( "%s, %s, or %s" ), whiteSpace[0], whiteSpace[1], whiteSpace[2] ); + else if( whiteSpace.size() == 4 ) + badChars.Printf( _( "%s, %s, %s, or %s" ), + whiteSpace[0], whiteSpace[1], whiteSpace[2], whiteSpace[3] ); + else + wxCHECK_MSG( false, true, wxT( "Invalid illegal character in field validator." ) ); + + errorMsg.Printf( _( "The %s field cannot contain %s characters." ), fieldName, badChars ); + } + + if ( !errorMsg.empty() ) + { + m_validatorWindow->SetFocus(); + + wxMessageBox( errorMsg, _( "Field Validation Error" ), + wxOK | wxICON_EXCLAMATION, aParent ); + + return false; + } + + return true; +} diff --git a/eeschema/sch_validators.h b/eeschema/sch_validators.h new file mode 100644 index 00000000..6c34060c --- /dev/null +++ b/eeschema/sch_validators.h @@ -0,0 +1,72 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com + * Copyright (C) 2016 KiCad Developers, see change_log.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 + */ + +/** + * @file sch_validators.h + * @brief Defintions of control validators for schematic dialogs. + */ + +#ifndef _SCH_VALIDATORS_H_ +#define _SCH_VALIDATORS_H_ + + +#include + +/** + * class SCH_FILED_VALIDATOR + * + * is the text control validator used for validating the text allowed in library and + * schematic component fields. + * Note + * Reference field does not accept spaces + * Value field does not accept spaces in Component Library Editor, because in .lib component + * libraries, the value field is the component name in lib, and spaces are not allowed + * in component names in lib + */ +class SCH_FIELD_VALIDATOR : public wxTextValidator +{ + int m_fieldId; + bool m_isLibEditor; + +public: + SCH_FIELD_VALIDATOR( bool aIsCmplibEditor, int aFieldId, wxString* aValue = NULL ); + + SCH_FIELD_VALIDATOR( const SCH_FIELD_VALIDATOR& aValidator ); + + virtual wxObject* Clone() const { return new SCH_FIELD_VALIDATOR( *this ); } + + /** + * Function Validate + * + * overrides the default Validate() function provided by wxTextValidate to provide + * better error messages. + * + * @param aParent - a pointer to the parent window of the error message dialog. + * @return true if the text in the control is valid otherwise false. + */ + virtual bool Validate( wxWindow *aParent ); +}; + + +#endif // _SCH_VALIDATORS_H_ diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp new file mode 100644 index 00000000..927e44c1 --- /dev/null +++ b/eeschema/schedit.cpp @@ -0,0 +1,1163 @@ + /* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2013 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file schedit.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) +{ + int id = event.GetId(); + wxPoint pos; + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + pos = wxGetMousePosition(); + + pos.y += 20; + + // If needed, stop the current command and deselect current tool + switch( id ) + { + case wxID_CUT: + case wxID_COPY: + case ID_POPUP_CANCEL_CURRENT_COMMAND: + case ID_POPUP_SCH_ENTRY_SELECT_SLASH: + case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH: + case ID_POPUP_SCH_BEGIN_WIRE: + case ID_POPUP_SCH_BEGIN_BUS: + case ID_POPUP_END_LINE: + case ID_POPUP_SCH_SET_SHAPE_TEXT: + case ID_POPUP_SCH_CLEANUP_SHEET: + case ID_POPUP_SCH_END_SHEET: + case ID_POPUP_SCH_RESIZE_SHEET: + case ID_POPUP_IMPORT_HLABEL_TO_SHEETPIN: + case ID_POPUP_SCH_INIT_CMP: + case ID_POPUP_SCH_DISPLAYDOC_CMP: + case ID_POPUP_SCH_EDIT_CONVERT_CMP: + case ID_POPUP_DELETE_BLOCK: + case ID_POPUP_PLACE_BLOCK: + case ID_POPUP_ZOOM_BLOCK: + case ID_POPUP_DRAG_BLOCK: + case ID_POPUP_COPY_BLOCK: + case ID_POPUP_SCH_DELETE_NODE: + case ID_POPUP_SCH_DELETE_CONNECTION: + case ID_POPUP_SCH_ENTER_SHEET: + case ID_POPUP_SCH_LEAVE_SHEET: + case ID_POPUP_SCH_ADD_JUNCTION: + case ID_POPUP_SCH_ADD_LABEL: + case ID_POPUP_SCH_GETINFO_MARKER: + + /* At this point: Do nothing. these commands do not need to stop the + * current command (mainly a block command) or reset the current state + * They will be executed later, in next switch structure. + */ + break; + + case ID_POPUP_SCH_DELETE_CMP: + case ID_POPUP_SCH_DELETE: + + // Stop the current command (if any) but keep the current tool + m_canvas->EndMouseCapture(); + break; + + default: + + // Stop the current command and deselect the current tool + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + break; + } + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + item = screen->GetCurItem(); // Can be modified by previous calls. + + switch( id ) + { + case ID_HIERARCHY: + InstallHierarchyFrame( pos ); + SetRepeatItem( NULL ); + break; + + case wxID_CUT: + if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE ) + break; + + screen->m_BlockLocate.SetCommand( BLOCK_DELETE ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + SetRepeatItem( NULL ); + SetSheetNumberAndCount(); + break; + + case wxID_PASTE: + HandleBlockBegin( &dc, BLOCK_PASTE, GetCrossHairPosition() ); + break; + + case ID_POPUP_SCH_ENTRY_SELECT_SLASH: + m_canvas->MoveCursorToCrossHair(); + SetBusEntryShape( &dc, dynamic_cast( item ), '/' ); + break; + + case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH: + m_canvas->MoveCursorToCrossHair(); + SetBusEntryShape( &dc, dynamic_cast( item ), '\\' ); + break; + + case ID_POPUP_CANCEL_CURRENT_COMMAND: + if( m_canvas->IsMouseCaptured() ) + { + m_canvas->EndMouseCapture(); + SetToolID( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString ); + } + else + { + SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); + } + + break; + + case ID_POPUP_END_LINE: + m_canvas->MoveCursorToCrossHair(); + EndSegment( &dc ); + break; + + case ID_POPUP_SCH_BEGIN_WIRE: + m_canvas->MoveCursorToCrossHair(); + OnLeftClick( &dc, GetCrossHairPosition() ); + break; + + case ID_POPUP_SCH_BEGIN_BUS: + m_canvas->MoveCursorToCrossHair(); + OnLeftClick( &dc, GetCrossHairPosition() ); + break; + + case ID_POPUP_SCH_SET_SHAPE_TEXT: + // Not used + break; + + case ID_POPUP_SCH_DELETE_NODE: + case ID_POPUP_SCH_DELETE_CONNECTION: + m_canvas->MoveCursorToCrossHair(); + DeleteConnection( id == ID_POPUP_SCH_DELETE_CONNECTION ); + screen->SetCurItem( NULL ); + SetRepeatItem( NULL ); + screen->TestDanglingEnds( m_canvas, &dc ); + m_canvas->Refresh(); + break; + + case ID_POPUP_SCH_BREAK_WIRE: + { + DLIST< SCH_ITEM > oldWires; + + oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor. + m_canvas->MoveCursorToCrossHair(); + screen->ExtractWires( oldWires, true ); + screen->BreakSegment( GetCrossHairPosition() ); + + if( oldWires.GetCount() != 0 ) + { + PICKED_ITEMS_LIST oldItems; + + oldItems.m_Status = UR_WIRE_IMAGE; + + while( oldWires.GetCount() != 0 ) + { + ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE ); + oldItems.PushItem( picker ); + } + + SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE ); + } + + screen->TestDanglingEnds( m_canvas, &dc ); + } + break; + + case ID_POPUP_SCH_DELETE_CMP: + case ID_POPUP_SCH_DELETE: + if( item == NULL ) + break; + + DeleteItem( item ); + screen->SetCurItem( NULL ); + SetRepeatItem( NULL ); + screen->TestDanglingEnds( m_canvas, &dc ); + SetSheetNumberAndCount(); + OnModify(); + break; + + case ID_POPUP_SCH_END_SHEET: + m_canvas->MoveCursorToCrossHair(); + addCurrentItemToList(); + break; + + case ID_POPUP_SCH_RESIZE_SHEET: + ReSizeSheet( (SCH_SHEET*) item, &dc ); + screen->TestDanglingEnds( m_canvas, &dc ); + break; + + case ID_POPUP_IMPORT_HLABEL_TO_SHEETPIN: + if( item != NULL && item->Type() == SCH_SHEET_T ) + screen->SetCurItem( ImportSheetPin( (SCH_SHEET*) item, &dc ) ); + break; + + case ID_POPUP_SCH_CLEANUP_SHEET: + if( item != NULL && item->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) item; + + if( !sheet->HasUndefinedPins() ) + { + DisplayInfoMessage( this, + _( "There are no undefined labels in this sheet to clean up." ) ); + return; + } + + if( !IsOK( this, _( "Do you wish to cleanup this sheet?" ) ) ) + return; + + /* Save sheet in undo list before cleaning up unreferenced hierarchical labels. */ + SaveCopyInUndoList( sheet, UR_CHANGED ); + sheet->CleanupSheet(); + OnModify(); + m_canvas->RefreshDrawingRect( sheet->GetBoundingBox() ); + } + break; + + case ID_POPUP_SCH_INIT_CMP: + m_canvas->MoveCursorToCrossHair(); + break; + + case ID_POPUP_SCH_EDIT_CONVERT_CMP: + + // Ensure the struct is a component (could be a struct of a component, like Field, text..) + if( item && item->Type() == SCH_COMPONENT_T ) + { + m_canvas->MoveCursorToCrossHair(); + ConvertPart( (SCH_COMPONENT*) item, &dc ); + } + + break; + + case ID_POPUP_SCH_DISPLAYDOC_CMP: + + // Ensure the struct is a component (could be a piece of a component, like Field, text..) + if( item && item->Type() == SCH_COMPONENT_T ) + { + if( PART_LIBS* libs = Prj().SchLibs() ) + { + LIB_ALIAS* entry = libs->FindLibraryEntry( ( (SCH_COMPONENT*) item )->GetPartName() ); + + if( entry && !!entry->GetDocFileName() ) + { + SEARCH_STACK* lib_search = Prj().SchSearchS(); + + GetAssociatedDocument( this, entry->GetDocFileName(), lib_search ); + } + } + } + break; + + case ID_POPUP_SCH_ENTER_SHEET: + + if( item && (item->Type() == SCH_SHEET_T) ) + { + m_CurrentSheet->Push( (SCH_SHEET*) item ); + DisplayCurrentSheet(); + } + + break; + + case ID_POPUP_SCH_LEAVE_SHEET: + if( m_CurrentSheet->Last() != g_RootSheet ) + { + m_CurrentSheet->Pop(); + DisplayCurrentSheet(); + } + + break; + + case wxID_COPY: // really this is a Save block for paste + screen->m_BlockLocate.SetCommand( BLOCK_SAVE ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_PLACE_BLOCK: + m_canvas->SetAutoPanRequest( false ); + m_canvas->MoveCursorToCrossHair(); + HandleBlockPlace( &dc ); + break; + + case ID_POPUP_ZOOM_BLOCK: + screen->m_BlockLocate.SetCommand( BLOCK_ZOOM ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_DELETE_BLOCK: + if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE ) + break; + + m_canvas->MoveCursorToCrossHair(); + screen->m_BlockLocate.SetCommand( BLOCK_DELETE ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + SetSheetNumberAndCount(); + break; + + case ID_POPUP_COPY_BLOCK: + if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE ) + break; + + m_canvas->MoveCursorToCrossHair(); + screen->m_BlockLocate.SetCommand( BLOCK_COPY ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_DRAG_BLOCK: + if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE ) + break; + + m_canvas->MoveCursorToCrossHair(); + screen->m_BlockLocate.SetCommand( BLOCK_DRAG ); + screen->m_BlockLocate.SetMessageBlock( this ); + HandleBlockEnd( &dc ); + break; + + case ID_POPUP_SCH_ADD_JUNCTION: + m_canvas->MoveCursorToCrossHair(); + screen->SetCurItem( AddJunction( &dc, GetCrossHairPosition(), true ) ); + screen->TestDanglingEnds( m_canvas, &dc ); + screen->SetCurItem( NULL ); + break; + + case ID_POPUP_SCH_ADD_LABEL: + case ID_POPUP_SCH_ADD_GLABEL: + screen->SetCurItem( CreateNewText( &dc, id == ID_POPUP_SCH_ADD_LABEL ? + LAYER_LOCLABEL : LAYER_GLOBLABEL ) ); + item = screen->GetCurItem(); + + if( item ) + addCurrentItemToList(); + + break; + + case ID_POPUP_SCH_GETINFO_MARKER: + if( item && item->Type() == SCH_MARKER_T ) + ( (SCH_MARKER*) item )->DisplayMarkerInfo( this ); + + break; + + default: // Log error: + wxFAIL_MSG( wxString::Format( wxT( "Cannot process command event ID %d" ), + event.GetId() ) ); + break; + } + + // End switch ( id ) (Command execution) + + if( GetToolId() == ID_NO_TOOL_SELECTED ) + SetRepeatItem( NULL ); +} + + +void SCH_EDIT_FRAME::OnMoveItem( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + if( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + { + // trying to move an item when there is a block at the same time is not acceptable + return; + } + + if( item == NULL ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( aEvent.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::MovableItems, + aEvent.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + } + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + switch( item->Type() ) + { + case SCH_LINE_T: + break; + + case SCH_JUNCTION_T: + case SCH_NO_CONNECT_T: + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_TEXT_T: + case SCH_COMPONENT_T: + case SCH_SHEET_PIN_T: + case SCH_FIELD_T: + case SCH_SHEET_T: + PrepareMoveItem( item, &dc ); + break; + + case SCH_BITMAP_T: + // move an image is a special case: + // we cannot undraw/redraw a bitmap just using our xor mode + // the MoveImage function handle this undraw/redraw difficulty + // By redrawing the full bounding box + MoveImage( (SCH_BITMAP*) item, &dc ); + break; + + case SCH_MARKER_T: + // Moving a marker has no sense + break; + + default: + // Unknown items cannot be moved + wxFAIL_MSG( wxString::Format( + wxT( "Cannot move item type %d" ), item->Type() ) ); + break; + } + + if( GetToolId() == ID_NO_TOOL_SELECTED ) + SetRepeatItem( NULL ); +} + + +void SCH_EDIT_FRAME::OnCancelCurrentCommand( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + + if( screen->IsBlockActive() ) + { + m_canvas->SetCursor( (wxStockCursor) m_canvas->GetDefaultCursor() ); + screen->ClearBlockCommand(); + + // Stop the current command (if any) but keep the current tool + m_canvas->EndMouseCapture(); + } + else + { + if( m_canvas->IsMouseCaptured() ) // Stop the current command but keep the current tool + m_canvas->EndMouseCapture(); + else // Deselect current tool + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + } +} + + +void SCH_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) +{ + int id = aEvent.GetId(); + + // Stop the current command and deselect the current tool. + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + + switch( id ) + { + case ID_NO_TOOL_SELECTED: + SetToolID( id, m_canvas->GetDefaultCursor(), _( "No tool selected" ) ); + break; + + case ID_HIERARCHY_PUSH_POP_BUTT: + SetToolID( id, wxCURSOR_HAND, _( "Descend or ascend hierarchy" ) ); + break; + + case ID_NOCONN_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add no connect" ) ); + break; + + case ID_WIRE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add wire" ) ); + break; + + case ID_BUS_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add bus" ) ); + break; + + case ID_LINE_COMMENT_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add lines" ) ); + break; + + case ID_JUNCTION_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add junction" ) ); + break; + + case ID_LABEL_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add label" ) ); + break; + + case ID_GLABEL_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add global label" ) ); + break; + + case ID_HIERLABEL_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add hierarchical label" ) ); + break; + + case ID_TEXT_COMMENT_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add text" ) ); + break; + + case ID_ADD_IMAGE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add image" ) ); + break; + + case ID_WIRETOBUS_ENTRY_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add wire to bus entry" ) ); + break; + + case ID_BUSTOBUS_ENTRY_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add bus to bus entry" ) ); + break; + + case ID_SHEET_SYMBOL_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add sheet" ) ); + break; + + case ID_SHEET_PIN_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add sheet pins" ) ); + break; + + case ID_IMPORT_HLABEL_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Import sheet pins" ) ); + break; + + case ID_SCH_PLACE_COMPONENT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add component" ) ); + break; + + case ID_PLACE_POWER_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add power" ) ); + break; + + case ID_SCHEMATIC_DELETE_ITEM_BUTT: + SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) ); + break; + + default: + SetRepeatItem( NULL ); + } + + // Simulate left click event if we got here from a hot key. + if( aEvent.GetClientObject() != NULL ) + { + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxPoint pos = data->GetPosition(); + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + OnLeftClick( &dc, pos ); + } +} + + +void SCH_EDIT_FRAME::OnUpdateSelectTool( wxUpdateUIEvent& aEvent ) +{ + if( aEvent.GetEventObject() == m_drawToolBar ) + aEvent.Check( GetToolId() == aEvent.GetId() ); +} + + +void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection ) +{ + PICKED_ITEMS_LIST pickList; + SCH_SCREEN* screen = GetScreen(); + wxPoint pos = GetCrossHairPosition(); + + if( screen->GetConnection( pos, pickList, aFullConnection ) != 0 ) + { + DeleteItemsInList( m_canvas, pickList ); + OnModify(); + } +} + + +bool SCH_EDIT_FRAME::DeleteItemAtCrossHair( wxDC* DC ) +{ + SCH_ITEM* item; + SCH_SCREEN* screen = GetScreen(); + + item = LocateItem( GetCrossHairPosition(), SCH_COLLECTOR::ParentItems ); + + if( item ) + { + bool itemHasConnections = item->IsConnectable(); + + screen->SetCurItem( NULL ); + SetRepeatItem( NULL ); + DeleteItem( item ); + + if( itemHasConnections ) + screen->TestDanglingEnds( m_canvas, DC ); + + OnModify(); + return true; + } + + return false; +} + +// This function is a callback function, called by the mouse cursor movin event +// when an item is currently moved +static void moveItemWithMouseCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aPosition, bool aErase ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + wxCHECK_RET( (item != NULL), wxT( "Cannot move invalid schematic item." ) ); + + SCH_COMPONENT* cmp = NULL; + + if( item->Type() == SCH_COMPONENT_T ) + cmp = static_cast< SCH_COMPONENT* >( item ); + +#ifndef USE_WX_OVERLAY + // Erase the current item at its current position. + if( aErase ) + { + if( cmp ) // Use fast mode (do not draw pin texts) + cmp->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, UNSPECIFIED_COLOR, false ); + else + item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); + } +#endif + + wxPoint cpos = aPanel->GetParent()->GetCrossHairPosition(); + cpos -= item->GetStoredPos(); + + item->SetPosition( cpos ); + + // Draw the item item at it's new position. + item->SetWireImage(); // While moving, the item may choose to render differently + + if( cmp ) // Use fast mode (do not draw pin texts) + cmp->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, UNSPECIFIED_COLOR, false ); + else + item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); +} + + +static void abortMoveItem( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + SCH_EDIT_FRAME* parent = (SCH_EDIT_FRAME*) aPanel->GetParent(); + + parent->SetRepeatItem( NULL ); + screen->SetCurItem( NULL ); + + if( item == NULL ) /* no current item */ + return; + + if( item->IsNew() ) + { + delete item; + item = NULL; + } + else + { + SCH_ITEM* oldItem = parent->GetUndoItem(); + + SCH_ITEM* currentItem; + + // Items that are children of other objects are undone by swapping the contents + // of the parent items. + if( (item->Type() == SCH_SHEET_PIN_T) || (item->Type() == SCH_FIELD_T) ) + { + currentItem = (SCH_ITEM*) item->GetParent(); + } + else + { + currentItem = item; + } + + wxCHECK_RET( oldItem != NULL && currentItem->Type() == oldItem->Type(), + wxT( "Cannot restore undefined or bad last schematic item." ) ); + + // Never delete existing item, because it can be referenced by an undo/redo command + // Just restore its data + currentItem->SwapData( oldItem ); + + // Erase the wire representation before the 'normal' view is drawn. + if ( item->IsWireImage() ) + item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); + + item->ClearFlags(); + } + + aPanel->Refresh(); +} + + +void SCH_EDIT_FRAME::PrepareMoveItem( SCH_ITEM* aItem, wxDC* aDC ) +{ + wxCHECK_RET( aItem != NULL, wxT( "Cannot move invalid schematic item" ) ); + + SetRepeatItem( NULL ); + + if( !aItem->IsNew() ) + { + if( (aItem->Type() == SCH_SHEET_PIN_T) || (aItem->Type() == SCH_FIELD_T) ) + SetUndoItem( (SCH_ITEM*) aItem->GetParent() ); + else + SetUndoItem( aItem ); + } + + aItem->SetFlags( IS_MOVED ); + + // For some items, moving the cursor to anchor is not good + // (for instance large hierarchical sheets od componants can have + // the anchor position outside the canvas) + // these items return IsMovableFromAnchorPoint() == false + // For these items, do not wrap the cursor + if( aItem->IsMovableFromAnchorPoint() ) + { + SetCrossHairPosition( aItem->GetPosition() ); + m_canvas->MoveCursorToCrossHair(); + aItem->SetStoredPos( wxPoint( 0,0 ) ); + } + else + aItem->SetStoredPos( GetCrossHairPosition() - aItem->GetPosition() ); + + OnModify(); + + GetScreen()->SetCurItem( aItem ); + m_canvas->SetMouseCapture( moveItemWithMouseCursor, abortMoveItem ); + + m_canvas->Refresh(); +} + + +void SCH_EDIT_FRAME::OnRotate( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + // Allows block rotate operation on hot key. + if( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + { + screen->m_BlockLocate.SetCommand( BLOCK_ROTATE ); + HandleBlockEnd( &dc ); + return; + } + + if( item == NULL ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( aEvent.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::RotatableItems, + aEvent.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + } + + switch( item->Type() ) + { + case SCH_COMPONENT_T: + if( aEvent.GetId() == ID_SCH_ROTATE_CLOCKWISE ) + OrientComponent( CMP_ROTATE_CLOCKWISE ); + else if( aEvent.GetId() == ID_SCH_ROTATE_COUNTERCLOCKWISE ) + OrientComponent( CMP_ROTATE_COUNTERCLOCKWISE ); + else + wxFAIL_MSG( wxT( "Unknown rotate item command ID." ) ); + + break; + + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + m_canvas->MoveCursorToCrossHair(); + ChangeTextOrient( (SCH_TEXT*) item, &dc ); + break; + + case SCH_FIELD_T: + m_canvas->MoveCursorToCrossHair(); + RotateField( (SCH_FIELD*) item, &dc ); + break; + + case SCH_BITMAP_T: + RotateImage( (SCH_BITMAP*) item ); + break; + + case SCH_SHEET_T: + if( !item->IsNew() ) // rotate a sheet during its creation has no sense + { + bool retCCW = ( aEvent.GetId() == ID_SCH_ROTATE_COUNTERCLOCKWISE ); + RotateHierarchicalSheet( static_cast( item ), retCCW ); + } + + break; + + case SCH_JUNCTION_T: + case SCH_NO_CONNECT_T: + // these items are not rotated, because rotation does not change them. + break; + + default: + // Other items (wires...) cannot be rotated, at least during creation + if( item->IsNew() ) + break; + + wxFAIL_MSG( wxString::Format( wxT( "Cannot rotate schematic item type %s." ), + GetChars( item->GetClass() ) ) ); + } + + if( item->GetFlags() == 0 ) + screen->SetCurItem( NULL ); +} + + +void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + if( item == NULL ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( aEvent.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + // Set the locat filter, according to the edit command + const KICAD_T* filterList = SCH_COLLECTOR::EditableItems; + const KICAD_T* filterListAux = NULL; + + switch( aEvent.GetId() ) + { + case ID_SCH_EDIT_COMPONENT_REFERENCE: + filterList = SCH_COLLECTOR::CmpFieldReferenceOnly; + filterListAux = SCH_COLLECTOR::ComponentsOnly; + break; + + case ID_SCH_EDIT_COMPONENT_VALUE: + filterList = SCH_COLLECTOR::CmpFieldValueOnly; + filterListAux = SCH_COLLECTOR::ComponentsOnly; + break; + + case ID_SCH_EDIT_COMPONENT_FOOTPRINT: + filterList = SCH_COLLECTOR::CmpFieldFootprintOnly; + filterListAux = SCH_COLLECTOR::ComponentsOnly; + break; + + default: + break; + } + + item = LocateAndShowItem( data->GetPosition(), filterList, aEvent.GetInt() ); + + // If no item found, and if an auxiliary filter exists, try to use it + if( !item && filterListAux ) + item = LocateAndShowItem( data->GetPosition(), filterListAux, aEvent.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + } + + switch( item->Type() ) + { + case SCH_COMPONENT_T: + { + switch( aEvent.GetId() ) + { + case ID_SCH_EDIT_COMPONENT_REFERENCE: + EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( REFERENCE ) ); + break; + + case ID_SCH_EDIT_COMPONENT_VALUE: + EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( VALUE ) ); + break; + + case ID_SCH_EDIT_COMPONENT_FOOTPRINT: + EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( FOOTPRINT ) ); + break; + + case ID_SCH_EDIT_ITEM: + EditComponent( (SCH_COMPONENT*) item ); + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Invalid schematic component edit command ID %d" ), + aEvent.GetId() ) ); + } + + break; + } + + case SCH_SHEET_T: + if( EditSheet( (SCH_SHEET*) item, m_CurrentSheet ) ) + m_canvas->Refresh(); + break; + + case SCH_SHEET_PIN_T: + EditSheetPin( (SCH_SHEET_PIN*) item, true ); + break; + + case SCH_TEXT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + EditSchematicText( (SCH_TEXT*) item ); + break; + + case SCH_FIELD_T: + EditComponentFieldText( (SCH_FIELD*) item ); + break; + + case SCH_BITMAP_T: + EditImage( (SCH_BITMAP*) item ); + break; + + case SCH_LINE_T: // These items have no param to edit + case SCH_MARKER_T: + case SCH_JUNCTION_T: + case SCH_NO_CONNECT_T: + break; + + default: // Unexpected item + wxFAIL_MSG( wxString::Format( wxT( "Cannot edit schematic item type %s." ), + GetChars( item->GetClass() ) ) ); + } + + if( item->GetFlags() == 0 ) + screen->SetCurItem( NULL ); +} + + +void SCH_EDIT_FRAME::OnDragItem( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + // The easiest way to handle a menu or a hot key drag command + // is to simulate a block drag command + // + // When a drag item is requested, some items use a BLOCK_DRAG_ITEM drag type + // an some items use a BLOCK_DRAG drag type (mainly a junction) + // a BLOCK_DRAG collects all items in a block (here a 2x2 rect centered on the cursor) + // and BLOCK_DRAG_ITEM drag only the selected item + BLOCK_COMMAND_T dragType = BLOCK_DRAG_ITEM; + + if( item == NULL ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( aEvent.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::DraggableItems, + aEvent.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + + // When a junction or a node is found, a BLOCK_DRAG is better + if( m_collectedItems.IsCorner() || m_collectedItems.IsNode( false ) + || m_collectedItems.IsDraggableJunction() ) + dragType = BLOCK_DRAG; + } + + switch( item->Type() ) + { + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + case SCH_LINE_T: + case SCH_JUNCTION_T: + case SCH_COMPONENT_T: + case SCH_LABEL_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIERARCHICAL_LABEL_T: + case SCH_SHEET_T: + m_canvas->MoveCursorToCrossHair(); + + if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK ) + { + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + if( !HandleBlockBegin( &dc, dragType, GetCrossHairPosition() ) ) + break; + + // Give a non null size to the search block: + screen->m_BlockLocate.Inflate( 1 ); + HandleBlockEnd( &dc ); + } + + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Cannot drag schematic item type %s." ), + GetChars( item->GetClass() ) ) ); + } +} + + +void SCH_EDIT_FRAME::OnOrient( wxCommandEvent& aEvent ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + INSTALL_UNBUFFERED_DC( dc, m_canvas ); + + // Allows block rotate operation on hot key. + if( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK ) + { + if( aEvent.GetId() == ID_SCH_MIRROR_X ) + { + m_canvas->MoveCursorToCrossHair(); + screen->m_BlockLocate.SetMessageBlock( this ); + screen->m_BlockLocate.SetCommand( BLOCK_MIRROR_X ); + HandleBlockEnd( &dc ); + } + else if( aEvent.GetId() == ID_SCH_MIRROR_Y ) + { + m_canvas->MoveCursorToCrossHair(); + screen->m_BlockLocate.SetMessageBlock( this ); + screen->m_BlockLocate.SetCommand( BLOCK_MIRROR_Y ); + HandleBlockEnd( &dc ); + } + else + { + wxFAIL_MSG( wxT( "Unknown block oriention command ID." ) ); + } + + return; + } + + if( item == NULL ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( aEvent.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::OrientableItems, + aEvent.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + } + + + switch( item->Type() ) + { + case SCH_COMPONENT_T: + if( aEvent.GetId() == ID_SCH_MIRROR_X ) + OrientComponent( CMP_MIRROR_X ); + else if( aEvent.GetId() == ID_SCH_MIRROR_Y ) + OrientComponent( CMP_MIRROR_Y ); + else if( aEvent.GetId() == ID_SCH_ORIENT_NORMAL ) + OrientComponent( CMP_NORMAL ); + else + wxFAIL_MSG( wxT( "Invalid orient schematic component command ID." ) ); + + break; + + case SCH_BITMAP_T: + if( aEvent.GetId() == ID_SCH_MIRROR_X ) + MirrorImage( (SCH_BITMAP*) item, true ); + else if( aEvent.GetId() == ID_SCH_MIRROR_Y ) + MirrorImage( (SCH_BITMAP*) item, false ); + + break; + + case SCH_SHEET_T: + if( aEvent.GetId() == ID_SCH_MIRROR_X ) + MirrorSheet( (SCH_SHEET*) item, true ); + else if( aEvent.GetId() == ID_SCH_MIRROR_Y ) + MirrorSheet( (SCH_SHEET*) item, false ); + + break; + + default: + // This object cannot be oriented. + ; + } + + if( item->GetFlags() == 0 ) + screen->SetCurItem( NULL ); +} diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp new file mode 100644 index 00000000..7c539d03 --- /dev/null +++ b/eeschema/schematic_undo_redo.cpp @@ -0,0 +1,382 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file schematic_undo_redo.cpp + * @brief Eeschema undo and redo functions for schematic editor. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Functions to undo and redo edit commands. + * commands to undo are stored in CurrentScreen->m_UndoList + * commands to redo are stored in CurrentScreen->m_RedoList + * + * m_UndoList and m_RedoList handle a std::vector of PICKED_ITEMS_LIST + * Each PICKED_ITEMS_LIST handle a std::vector of pickers (class ITEM_PICKER), + * that store the list of schematic items that are concerned by the command to + * undo or redo and is created for each command to undo (handle also a command + * to redo). each picker has a pointer pointing to an item to undo or redo (in + * fact: deleted, added or modified), and has a pointer to a copy of this item, + * when this item has been modified (the old values of parameters are + * therefore saved) + * + * there are 3 cases: + * - delete item(s) command + * - change item(s) command + * - add item(s) command + * and 2 cases for block: + * - move list of items + * - mirror (Y) list of items + * + * Undo command + * - delete item(s) command: + * => deleted items are moved in undo list + * + * - change item(s) command + * => A copy of item(s) is made (a DrawPickedStruct list of wrappers) + * the .m_Link member of each wrapper points the modified item. + * the .m_Item member of each wrapper points the old copy of this item. + * + * - add item(s) command + * =>A list of item(s) is made. The .m_Item member of each wrapper points + * the new item. + * + * Redo command + * - delete item(s) old command: + * => deleted items are moved in GetDrawItems() list, and in + * + * - change item(s) command + * => the copy of item(s) is moved in Undo list + * + * - add item(s) command + * => The list of item(s) is used to create a deleted list in undo + * list(same as a delete command) + * + * Some block operations that change items can be undone without memorized + * items, just the coordinates of the transform: move list of items (undo/ + * redo is made by moving with the opposite move vector) mirror (Y) and flip + * list of items (undo/redo is made by mirror or flip items) so they are + * handled specifically. + * + * A problem is the hierarchical sheet handling. + * the data associated (sub-hierarchy, undo/redo list) is deleted only + * when the sheet is really deleted (i.e. when deleted from undo or redo list) + * This is handled by its destructor. + */ + + +/* Used if undo / redo command: + * swap data between Item and its copy, pointed by its .m_Image member + * swapped data is data modified by edition, so not all values are swapped + */ + +void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem, + UNDO_REDO_T aCommandType, + const wxPoint& aTransformPoint ) +{ + /* Does not save a null item or a UR_WIRE_IMAGE command type. UR_WIRE_IMAGE commands + * are handled by the overloaded version of SaveCopyInUndoList that takes a reference + * to a PICKED_ITEMS_LIST. + */ + if( aItem == NULL || aCommandType == UR_WIRE_IMAGE ) + return; + + PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); + commandToUndo->m_TransformPoint = aTransformPoint; + + ITEM_PICKER itemWrapper( aItem, aCommandType ); + itemWrapper.SetFlags( aItem->GetFlags() ); + + switch( aCommandType ) + { + case UR_CHANGED: /* Create a copy of item */ + itemWrapper.SetLink( DuplicateStruct( aItem, true ) ); + commandToUndo->PushItem( itemWrapper ); + break; + + case UR_NEW: + case UR_DELETED: + case UR_ROTATED: + case UR_MOVED: + commandToUndo->PushItem( itemWrapper ); + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), + aCommandType ) ); + break; + } + + if( commandToUndo->GetCount() ) + { + /* Save the copy in undo list */ + GetScreen()->PushCommandToUndoList( commandToUndo ); + + /* Clear redo list, because after new save there is no redo to do */ + GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); + } + else + { + delete commandToUndo; + } +} + + +void SCH_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, + UNDO_REDO_T aTypeCommand, + const wxPoint& aTransformPoint ) +{ + PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); + + commandToUndo->m_TransformPoint = aTransformPoint; + commandToUndo->m_Status = aTypeCommand; + + // Copy picker list: + commandToUndo->CopyList( aItemsList ); + + // Verify list, and creates data if needed + for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ ) + { + SCH_ITEM* item = (SCH_ITEM*) commandToUndo->GetPickedItem( ii ); + wxASSERT( item ); + + UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii ); + + if( command == UR_UNSPECIFIED ) + { + command = aTypeCommand; + commandToUndo->SetPickedItemStatus( command, ii ); + } + + switch( command ) + { + case UR_CHANGED: /* Create a copy of item */ + + /* If needed, create a copy of item, and put in undo list + * in the picker, as link + * If this link is not null, the copy is already done + */ + if( commandToUndo->GetPickedItemLink( ii ) == NULL ) + commandToUndo->SetPickedItemLink( DuplicateStruct( item, true ), ii ); + + wxASSERT( commandToUndo->GetPickedItemLink( ii ) ); + break; + + case UR_MOVED: + case UR_MIRRORED_Y: + case UR_MIRRORED_X: + case UR_ROTATED: + case UR_NEW: + case UR_DELETED: + case UR_EXCHANGE_T: + case UR_WIRE_IMAGE: + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Unknown undo/redo command %d" ), command ) ); + break; + } + } + + if( commandToUndo->GetCount() || aTypeCommand == UR_WIRE_IMAGE ) + { + /* Save the copy in undo list */ + GetScreen()->PushCommandToUndoList( commandToUndo ); + + /* Clear redo list, because after new save there is no redo to do */ + GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); + } + else // Should not occur + { + delete commandToUndo; + } +} + + +void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand ) +{ + SCH_ITEM* item; + SCH_ITEM* alt_item; + + // Exchange the current wires, buses, and junctions with the copy save by the last edit. + if( aList->m_Status == UR_WIRE_IMAGE ) + { + DLIST< SCH_ITEM > oldWires; + + // Prevent items from being deleted when the DLIST goes out of scope. + oldWires.SetOwnership( false ); + + // Remove all of the wires, buses, and junctions from the current screen. + GetScreen()->ExtractWires( oldWires, false ); + + // Copy the saved wires, buses, and junctions to the current screen. + for( unsigned int i = 0; i < aList->GetCount(); i++ ) + GetScreen()->Append( (SCH_ITEM*) aList->GetPickedItem( i ) ); + + aList->ClearItemsList(); + + // Copy the previous wires, buses, and junctions to the picked item list for the + // redo operation. + while( oldWires.GetCount() != 0 ) + { + ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE ); + aList->PushItem( picker ); + } + + return; + } + + // Undo in the reverse order of list creation: (this can allow stacked changes like the + // same item can be changes and deleted in the same complex command. + for( int ii = aList->GetCount() - 1; ii >= 0; ii-- ) + { + item = (SCH_ITEM*) aList->GetPickedItem( ii ); + wxASSERT( item ); + + item->ClearFlags(); + + SCH_ITEM* image = (SCH_ITEM*) aList->GetPickedItemLink( ii ); + + switch( aList->GetPickedItemStatus( ii ) ) + { + case UR_CHANGED: /* Exchange old and new data for each item */ + item->SwapData( image ); + break; + + case UR_NEW: /* new items are deleted */ + aList->SetPickedItemStatus( UR_DELETED, ii ); + GetScreen()->Remove( item ); + break; + + case UR_DELETED: /* deleted items are put in the draw item list, as new items */ + aList->SetPickedItemStatus( UR_NEW, ii ); + GetScreen()->Append( item ); + break; + + case UR_MOVED: + item->ClearFlags(); + item->SetFlags( aList->GetPickerFlags( ii ) ); + item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); + item->ClearFlags(); + break; + + case UR_MIRRORED_Y: + item->MirrorY( aList->m_TransformPoint.x ); + break; + + case UR_MIRRORED_X: + item->MirrorX( aList->m_TransformPoint.y ); + break; + + case UR_ROTATED: + // To undo a rotate 90 deg transform we must rotate 270 deg to undo + // and 90 deg to redo: + item->Rotate( aList->m_TransformPoint ); + + if( aRedoCommand ) + break; // A only one rotate transform is OK + + // Make 3 rotate 90 deg transforms is this is actually an undo command + item->Rotate( aList->m_TransformPoint ); + item->Rotate( aList->m_TransformPoint ); + break; + + case UR_EXCHANGE_T: + alt_item = (SCH_ITEM*) aList->GetPickedItemLink( ii ); + alt_item->SetNext( NULL ); + alt_item->SetBack( NULL ); + GetScreen()->Remove( item ); + GetScreen()->Append( alt_item ); + aList->SetPickedItem( alt_item, ii ); + aList->SetPickedItemLink( item, ii ); + break; + + default: + wxFAIL_MSG( wxString::Format( wxT( "Unknown undo/redo command %d" ), + aList->GetPickedItemStatus( ii ) ) ); + break; + } + } +} + + +void SCH_EDIT_FRAME::GetSchematicFromUndoList( wxCommandEvent& event ) +{ + if( GetScreen()->GetUndoCommandCount() <= 0 ) + return; + + /* Get the old list */ + PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); + + /* Undo the command */ + PutDataInPreviousState( List, false ); + + /* Put the old list in RedoList */ + List->ReversePickersListOrder(); + GetScreen()->PushCommandToRedoList( List ); + + OnModify(); + SetSheetNumberAndCount(); + + GetScreen()->TestDanglingEnds(); + m_canvas->Refresh(); +} + + +void SCH_EDIT_FRAME::GetSchematicFromRedoList( wxCommandEvent& event ) +{ + if( GetScreen()->GetRedoCommandCount() == 0 ) + return; + + /* Get the old list */ + PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); + + /* Redo the command: */ + PutDataInPreviousState( List, true ); + + /* Put the old list in UndoList */ + List->ReversePickersListOrder(); + GetScreen()->PushCommandToUndoList( List ); + + OnModify(); + SetSheetNumberAndCount(); + + GetScreen()->TestDanglingEnds(); + m_canvas->Refresh(); +} diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp new file mode 100644 index 00000000..25685760 --- /dev/null +++ b/eeschema/schframe.cpp @@ -0,0 +1,1320 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2013 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 + */ + +/** + * @file schframe.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +// non-member so it can be moved easily, and kept REALLY private. +// Do NOT Clear() in here. +static void add_search_paths( SEARCH_STACK* aDst, const SEARCH_STACK& aSrc, int aIndex ) +{ + for( unsigned i=0; iAddPaths( aSrc[i], aIndex ); +} + + +// non-member so it can be moved easily, and kept REALLY private. +// Do NOT Clear() in here. +static void add_search_paths( SEARCH_STACK* aDst, wxConfigBase* aCfg, int aIndex ) +{ + for( int i=1; true; ++i ) + { + wxString key = wxString::Format( wxT( "LibraryPath%d" ), i ); + wxString upath = aCfg->Read( key, wxEmptyString ); + + if( !upath ) + break; + + aDst->AddPaths( upath, aIndex ); + } +} + +//------------------------------------------------ + +SEARCH_STACK* PROJECT::SchSearchS() +{ + SEARCH_STACK* ss = (SEARCH_STACK*) GetElem( PROJECT::ELEM_SCH_SEARCH_STACK ); + + wxASSERT( !ss || dynamic_cast( GetElem( PROJECT::ELEM_SCH_SEARCH_STACK ) ) ); + + if( !ss ) + { + ss = new SEARCH_STACK(); + + // Make PROJECT the new SEARCH_STACK owner. + SetElem( PROJECT::ELEM_SCH_SEARCH_STACK, ss ); + + // to the empty SEARCH_STACK for SchSearchS(), add project dir as first + ss->AddPaths( m_project_name.GetPath() ); + + // next add the paths found in *.pro, variable "LibDir" + wxString libDir; + + try + { + PART_LIBS::LibNamesAndPaths( this, false, &libDir ); + } + catch( const IO_ERROR& ioe ) + { + DBG(printf( "%s: %s\n", __func__, TO_UTF8( ioe.errorText ) );) + } + + if( !!libDir ) + { + wxArrayString paths; + + SEARCH_STACK::Split( &paths, libDir ); + + for( unsigned i =0; iAddPaths( path ); // at the end + } + } + + // append all paths from aSList + add_search_paths( ss, Kiface().KifaceSearch(), -1 ); + + // addLibrarySearchPaths( SEARCH_STACK* aSP, wxConfigBase* aCfg ) + // This is undocumented, but somebody wanted to store !schematic! + // library search paths in the .kicad_common file? + add_search_paths( ss, Pgm().CommonSettings(), -1 ); + } + + return ss; +} + + +PART_LIBS* PROJECT::SchLibs() +{ + PART_LIBS* libs = (PART_LIBS*) GetElem( PROJECT::ELEM_SCH_PART_LIBS ); + + wxASSERT( !libs || dynamic_cast( libs ) ); + + if( !libs ) + { + libs = new PART_LIBS(); + + // Make PROJECT the new PART_LIBS owner. + SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs ); + + try + { + libs->LoadAllLibraries( this ); + } + catch( const PARSE_ERROR& pe ) + { + wxString lib_list = UTF8( pe.inputLine ); + wxWindow* parent = 0; // Pgm().App().GetTopWindow(); + + // parent of this dialog cannot be NULL since that breaks the Kiway() chain. + HTML_MESSAGE_BOX dlg( parent, _( "Not Found" ) ); + + dlg.MessageSet( _( "The following libraries were not found:" ) ); + + dlg.ListSet( lib_list ); + + dlg.Layout(); + + dlg.ShowModal(); + } + catch( const IO_ERROR& ioe ) + { + DisplayError( NULL, ioe.errorText ); + } + } + + return libs; +} + +/* +NETLIST_OBJECT_LIST* PROJECT::Netlist() +{ + NETLIST_OBJECT_LIST* netlist = (NETLIST_OBJECT_LIST*) GetElem( PROJECT::ELEM_SCH_NETLIST ); + + wxASSERT( !libs || dynamic_cast( netlist ) ); + + if( !netlist ) + { + netlist = new NETLIST_OBJECT_LIST(); + + // Make PROJECT the new NETLIST_OBJECT_LIST owner. + SetElem( PROJECT::ELEM_SCH_NETLIST, netlist ); + } +} +*/ + +//----------------------------------------------- + + +BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME ) + EVT_SOCKET( ID_EDA_SOCKET_EVENT_SERV, EDA_DRAW_FRAME::OnSockRequestServer ) + EVT_SOCKET( ID_EDA_SOCKET_EVENT, EDA_DRAW_FRAME::OnSockRequest ) + + EVT_CLOSE( SCH_EDIT_FRAME::OnCloseWindow ) + EVT_SIZE( SCH_EDIT_FRAME::OnSize ) + + EVT_MENU( ID_NEW_PROJECT, SCH_EDIT_FRAME::OnNewProject ) + EVT_MENU( ID_LOAD_PROJECT, SCH_EDIT_FRAME::OnLoadProject ) + + EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, SCH_EDIT_FRAME::OnLoadFile ) + + EVT_MENU( ID_APPEND_PROJECT, SCH_EDIT_FRAME::OnAppendProject ) + + EVT_TOOL( ID_NEW_PROJECT, SCH_EDIT_FRAME::OnNewProject ) + EVT_TOOL( ID_LOAD_PROJECT, SCH_EDIT_FRAME::OnLoadProject ) + + EVT_MENU( ID_SAVE_PROJECT, SCH_EDIT_FRAME::OnSaveProject ) + EVT_MENU( ID_UPDATE_ONE_SHEET, SCH_EDIT_FRAME::Save_File ) + EVT_MENU( ID_SAVE_ONE_SHEET_UNDER_NEW_NAME, SCH_EDIT_FRAME::Save_File ) + EVT_MENU( ID_GEN_PLOT_SCHEMATIC, SCH_EDIT_FRAME::PlotSchematic ) + EVT_MENU( ID_GEN_COPY_SHEET_TO_CLIPBOARD, EDA_DRAW_FRAME::CopyToClipboard ) + EVT_MENU( wxID_EXIT, SCH_EDIT_FRAME::OnExit ) + + EVT_MENU( ID_POPUP_SCH_COPY_ITEM, SCH_EDIT_FRAME::OnCopySchematicItemRequest ) + + EVT_MENU( ID_CONFIG_REQ, SCH_EDIT_FRAME::InstallConfigFrame ) + EVT_MENU( ID_CONFIG_SAVE, SCH_EDIT_FRAME::Process_Config ) + EVT_MENU( ID_CONFIG_READ, SCH_EDIT_FRAME::Process_Config ) + EVT_MENU_RANGE( ID_PREFERENCES_HOTKEY_START, ID_PREFERENCES_HOTKEY_END, + SCH_EDIT_FRAME::Process_Config ) + + EVT_MENU( ID_COLORS_SETUP, SCH_EDIT_FRAME::OnColorConfig ) + EVT_TOOL( wxID_PREFERENCES, SCH_EDIT_FRAME::OnPreferencesOptions ) + + EVT_TOOL( ID_RUN_LIBRARY, SCH_EDIT_FRAME::OnOpenLibraryEditor ) + EVT_TOOL( ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP, SCH_EDIT_FRAME::OnOpenLibraryEditor ) + EVT_TOOL( ID_TO_LIBVIEW, SCH_EDIT_FRAME::OnOpenLibraryViewer ) + EVT_TOOL( ID_RESCUE_CACHED, SCH_EDIT_FRAME::OnRescueProject ) + + EVT_TOOL( ID_RUN_PCB, SCH_EDIT_FRAME::OnOpenPcbnew ) + EVT_TOOL( ID_RUN_PCB_MODULE_EDITOR, SCH_EDIT_FRAME::OnOpenPcbModuleEditor ) + + EVT_TOOL( ID_RUN_CVPCB, SCH_EDIT_FRAME::OnOpenCvpcb ) + + EVT_TOOL( ID_SHEET_SET, EDA_DRAW_FRAME::Process_PageSettings ) + EVT_TOOL( ID_HIERARCHY, SCH_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( wxID_CUT, SCH_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( wxID_COPY, SCH_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( wxID_PASTE, SCH_EDIT_FRAME::Process_Special_Functions ) + EVT_TOOL( wxID_UNDO, SCH_EDIT_FRAME::GetSchematicFromUndoList ) + EVT_TOOL( wxID_REDO, SCH_EDIT_FRAME::GetSchematicFromRedoList ) + EVT_TOOL( ID_GET_ANNOTATE, SCH_EDIT_FRAME::OnAnnotate ) + EVT_TOOL( wxID_PRINT, SCH_EDIT_FRAME::OnPrint ) + EVT_TOOL( ID_GET_ERC, SCH_EDIT_FRAME::OnErc ) + EVT_TOOL( ID_GET_NETLIST, SCH_EDIT_FRAME::OnCreateNetlist ) + EVT_TOOL( ID_GET_TOOLS, SCH_EDIT_FRAME::OnCreateBillOfMaterials ) + EVT_TOOL( ID_FIND_ITEMS, SCH_EDIT_FRAME::OnFindItems ) + EVT_TOOL( wxID_REPLACE, SCH_EDIT_FRAME::OnFindItems ) + EVT_TOOL( ID_BACKANNO_ITEMS, SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile ) + EVT_TOOL( ID_SCH_MOVE_ITEM, SCH_EDIT_FRAME::OnMoveItem ) + EVT_MENU( wxID_HELP, EDA_DRAW_FRAME::GetKicadHelp ) + EVT_MENU( wxID_INDEX, EDA_DRAW_FRAME::GetKicadHelp ) + EVT_MENU( wxID_ABOUT, EDA_BASE_FRAME::GetKicadAbout ) + + // Tools and buttons for vertical toolbar. + EVT_TOOL( ID_NO_TOOL_SELECTED, SCH_EDIT_FRAME::OnSelectTool ) + EVT_TOOL_RANGE( ID_SCHEMATIC_VERTICAL_TOOLBAR_START, ID_SCHEMATIC_VERTICAL_TOOLBAR_END, + SCH_EDIT_FRAME::OnSelectTool ) + + EVT_MENU( ID_CANCEL_CURRENT_COMMAND, SCH_EDIT_FRAME::OnCancelCurrentCommand ) + EVT_MENU( ID_SCH_DRAG_ITEM, SCH_EDIT_FRAME::OnDragItem ) + EVT_MENU_RANGE( ID_SCH_ROTATE_CLOCKWISE, ID_SCH_ROTATE_COUNTERCLOCKWISE, + SCH_EDIT_FRAME::OnRotate ) + EVT_MENU_RANGE( ID_SCH_EDIT_ITEM, ID_SCH_EDIT_COMPONENT_FOOTPRINT, + SCH_EDIT_FRAME::OnEditItem ) + EVT_MENU_RANGE( ID_SCH_MIRROR_X, ID_SCH_ORIENT_NORMAL, SCH_EDIT_FRAME::OnOrient ) + EVT_MENU_RANGE( ID_POPUP_START_RANGE, ID_POPUP_END_RANGE, + SCH_EDIT_FRAME::Process_Special_Functions ) + + // Tools and buttons options toolbar + EVT_TOOL( ID_TB_OPTIONS_HIDDEN_PINS, SCH_EDIT_FRAME::OnSelectOptionToolbar ) + EVT_TOOL( ID_TB_OPTIONS_BUS_WIRES_ORIENT, SCH_EDIT_FRAME::OnSelectOptionToolbar ) + + EVT_MENU_RANGE( ID_POPUP_GENERAL_START_RANGE, ID_POPUP_GENERAL_END_RANGE, + SCH_EDIT_FRAME::Process_Special_Functions ) + EVT_MENU_RANGE( ID_POPUP_SCH_SELECT_UNIT1, ID_POPUP_SCH_SELECT_UNIT_CMP_MAX, + SCH_EDIT_FRAME::OnSelectUnit ) + EVT_MENU_RANGE( ID_POPUP_SCH_CHANGE_TYPE_TEXT, ID_POPUP_SCH_CHANGE_TYPE_TEXT_TO_COMMENT, + SCH_EDIT_FRAME::OnConvertTextType ) + + // Multple item selection context menu commands. + EVT_MENU_RANGE( ID_SELECT_ITEM_START, ID_SELECT_ITEM_END, SCH_EDIT_FRAME::OnSelectItem ) + + /* Handle user interface update events. */ + EVT_UPDATE_UI( wxID_CUT, SCH_EDIT_FRAME::OnUpdateBlockSelected ) + EVT_UPDATE_UI( wxID_COPY, SCH_EDIT_FRAME::OnUpdateBlockSelected ) + EVT_UPDATE_UI( wxID_PASTE, SCH_EDIT_FRAME::OnUpdatePaste ) + EVT_UPDATE_UI( ID_TB_OPTIONS_HIDDEN_PINS, SCH_EDIT_FRAME::OnUpdateHiddenPins ) + EVT_UPDATE_UI( ID_TB_OPTIONS_BUS_WIRES_ORIENT, SCH_EDIT_FRAME::OnUpdateBusOrientation ) + EVT_UPDATE_UI( ID_NO_TOOL_SELECTED, SCH_EDIT_FRAME::OnUpdateSelectTool ) + EVT_UPDATE_UI_RANGE( ID_SCHEMATIC_VERTICAL_TOOLBAR_START, ID_SCHEMATIC_VERTICAL_TOOLBAR_END, + SCH_EDIT_FRAME::OnUpdateSelectTool ) + EVT_UPDATE_UI( ID_SAVE_PROJECT, SCH_EDIT_FRAME::OnUpdateSave ) + EVT_UPDATE_UI( ID_UPDATE_ONE_SHEET, SCH_EDIT_FRAME::OnUpdateSaveSheet ) + EVT_UPDATE_UI( ID_POPUP_SCH_LEAVE_SHEET, SCH_EDIT_FRAME::OnUpdateHierarchySheet ) + + /* Search dialog events. */ + EVT_FIND_CLOSE( wxID_ANY, SCH_EDIT_FRAME::OnFindDialogClose ) + EVT_FIND_DRC_MARKER( wxID_ANY, SCH_EDIT_FRAME::OnFindDrcMarker ) + EVT_FIND( wxID_ANY, SCH_EDIT_FRAME::OnFindSchematicItem ) + EVT_FIND_REPLACE( wxID_ANY, SCH_EDIT_FRAME::OnFindReplace ) + EVT_FIND_REPLACE_ALL( wxID_ANY, SCH_EDIT_FRAME::OnFindReplace ) + +END_EVENT_TABLE() + + +SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ): + SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH, wxT( "Eeschema" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, SCH_EDIT_FRAME_NAME ), + m_item_to_repeat( 0 ) +{ + m_showAxis = false; // true to show axis + m_showBorderAndTitleBlock = true; // true to show sheet references + m_CurrentSheet = new SCH_SHEET_PATH; + m_DefaultSchematicFileName = NAMELESS_PROJECT; + m_DefaultSchematicFileName += wxT( ".sch" ); + m_showAllPins = false; + m_previewPosition = wxDefaultPosition; + m_previewSize = wxDefaultSize; + m_printMonochrome = true; + m_printSheetReference = true; + SetShowPageLimits( true ); + m_hotkeysDescrList = g_Schematic_Hokeys_Descr; + m_dlgFindReplace = NULL; + m_findReplaceData = new wxFindReplaceData( wxFR_DOWN ); + m_undoItem = NULL; + m_hasAutoSave = true; + + SetForceHVLines( true ); + SetSpiceAddReferencePrefix( false ); + SetSpiceUseNetcodeAsNetname( false ); + + // Give an icon + wxIcon icon; + icon.CopyFromBitmap( KiBitmap( icon_eeschema_xpm ) ); + SetIcon( icon ); + + // Initialize grid id to the default value (50 mils): + const int default_grid = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000; + m_LastGridSizeId = default_grid; + + LoadSettings( config() ); + + CreateScreens(); + + // Ensure m_LastGridSizeId is an offset inside the allowed schematic grid range + if( !GetScreen()->GridExists( m_LastGridSizeId + ID_POPUP_GRID_LEVEL_1000 ) ) + m_LastGridSizeId = default_grid; + + SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); + + if( m_canvas ) + m_canvas->SetEnableBlockCommands( true ); + + ReCreateMenuBar(); + ReCreateHToolbar(); + ReCreateVToolbar(); + ReCreateOptToolbar(); + + // Initialize common print setup dialog settings. + m_pageSetupData.GetPrintData().SetPrintMode( wxPRINT_MODE_PRINTER ); + m_pageSetupData.GetPrintData().SetQuality( wxPRINT_QUALITY_MEDIUM ); + m_pageSetupData.GetPrintData().SetBin( wxPRINTBIN_AUTO ); + m_pageSetupData.GetPrintData().SetNoCopies( 1 ); + + m_auimgr.SetManagedWindow( this ); + + EDA_PANEINFO horiz; + horiz.HorizontalToolbarPane(); + + EDA_PANEINFO vert; + vert.VerticalToolbarPane(); + + EDA_PANEINFO mesg; + mesg.MessageToolbarPane(); + + if( m_mainToolBar ) + m_auimgr.AddPane( m_mainToolBar, + wxAuiPaneInfo( horiz ).Name( wxT( "m_mainToolBar" ) ).Top().Row( 0 ) ); + + if( m_drawToolBar ) + m_auimgr.AddPane( m_drawToolBar, wxAuiPaneInfo( vert ).Name( wxT( "m_drawToolBar" ) ).Right() ); + + if( m_optionsToolBar ) + m_auimgr.AddPane( m_optionsToolBar, + wxAuiPaneInfo( vert ).Name( wxT( "m_optionsToolBar" ) ).Left() ); + + if( m_canvas ) + m_auimgr.AddPane( m_canvas, wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() ); + + if( m_messagePanel ) + m_auimgr.AddPane( m_messagePanel, wxAuiPaneInfo( mesg ).Name( wxT( "MsgPanel" ) ).Bottom(). + Layer(10) ); + + m_auimgr.Update(); + + // Now Drawpanel is sized, we can use BestZoom to show the component (if any) + GetScreen()->SetZoom( BestZoom() ); + + Zoom_Automatique( false ); +} + + +SCH_EDIT_FRAME::~SCH_EDIT_FRAME() +{ + delete m_item_to_repeat; // we own the cloned object, see this->SetRepeatItem() + + SetScreen( NULL ); + + delete m_CurrentSheet; // a SCH_SHEET_PATH, on the heap. + delete m_undoItem; + delete g_RootSheet; + delete m_findReplaceData; + + m_CurrentSheet = NULL; + m_undoItem = NULL; + g_RootSheet = NULL; + m_findReplaceData = NULL; +} + + +void SCH_EDIT_FRAME::SetRepeatItem( SCH_ITEM* aItem ) +{ + // we cannot store a pointer to an item in the display list here since + // that item may be deleted, such as part of a line concatonation or other. + // So simply always keep a copy of the object which is to be repeated. + + SCH_ITEM* old = m_item_to_repeat; + SCH_ITEM* cur = aItem; + + if( cur != old ) + { + if( cur ) + { + aItem = (SCH_ITEM*) cur->Clone(); + + // Clone() preserves the flags, we want 'em cleared. + aItem->ClearFlags(); + } + + m_item_to_repeat = aItem; + + delete old; + } +} + + +void SCH_EDIT_FRAME::SetSheetNumberAndCount() +{ + SCH_SCREEN* screen; + SCH_SCREENS s_list; + + /* Set the sheet count, and the sheet number (1 for root sheet) + */ + int sheet_count = g_RootSheet->CountSheets(); + int SheetNumber = 1; + wxString current_sheetpath = m_CurrentSheet->Path(); + SCH_SHEET_LIST sheetList; + + // Examine all sheets path to find the current sheets path, + // and count them from root to the current sheet path: + SCH_SHEET_PATH* sheet; + + for( sheet = sheetList.GetFirst(); sheet != NULL; sheet = sheetList.GetNext() ) + { + wxString sheetpath = sheet->Path(); + + if( sheetpath == current_sheetpath ) // Current sheet path found + break; + + SheetNumber++; /* Not found, increment sheet + * number before this current + * path */ + } + + for( screen = s_list.GetFirst(); screen != NULL; screen = s_list.GetNext() ) + { + screen->m_NumberOfScreens = sheet_count; + } + + GetScreen()->m_ScreenNumber = SheetNumber; +} + + +SCH_SCREEN* SCH_EDIT_FRAME::GetScreen() const +{ + return m_CurrentSheet->LastScreen(); +} + + +wxString SCH_EDIT_FRAME::GetScreenDesc() const +{ + wxString s = m_CurrentSheet->PathHumanReadable(); + + return s; +} + + +void SCH_EDIT_FRAME::CreateScreens() +{ + if( g_RootSheet == NULL ) + { + g_RootSheet = new SCH_SHEET(); + } + + if( g_RootSheet->GetScreen() == NULL ) + { + SCH_SCREEN* screen = new SCH_SCREEN( &Kiway() ); + screen->SetMaxUndoItems( m_UndoRedoCountMax ); + g_RootSheet->SetScreen( screen ); + SetScreen( g_RootSheet->GetScreen() ); + } + + g_RootSheet->GetScreen()->SetFileName( m_DefaultSchematicFileName ); + + m_CurrentSheet->Clear(); + m_CurrentSheet->Push( g_RootSheet ); + + if( GetScreen() == NULL ) + { + SCH_SCREEN* screen = new SCH_SCREEN( &Kiway() ); + screen->SetMaxUndoItems( m_UndoRedoCountMax ); + SetScreen( screen ); + } + + GetScreen()->SetZoom( 32.0 ); +} + + +SCH_SHEET_PATH& SCH_EDIT_FRAME::GetCurrentSheet() +{ + wxASSERT_MSG( m_CurrentSheet != NULL, wxT( "SCH_EDIT_FRAME m_CurrentSheet member is NULL." ) ); + + return *m_CurrentSheet; +} + + +void SCH_EDIT_FRAME::SetCurrentSheet( const SCH_SHEET_PATH& aSheet ) +{ + *m_CurrentSheet = aSheet; +} + + +void SCH_EDIT_FRAME::SetUndoItem( const SCH_ITEM* aItem ) +{ + // if aItem != NULL, delete a previous m_undoItem, if exists + // if aItme = NULL, just clear m_undoItem, + // because when calling SetUndoItem( NULL ), we only clear m_undoItem, + // because the owner of m_undoItem is no more me. + if( aItem && m_undoItem ) + { + delete m_undoItem; + } + + m_undoItem = NULL; + + if( aItem ) + m_undoItem = (SCH_ITEM*) aItem->Clone(); + +} + + +void SCH_EDIT_FRAME::SaveUndoItemInUndoList( SCH_ITEM* aItem ) +{ + wxCHECK_RET( aItem != NULL, + wxT( "Cannot swap undo item structures. Bad programmer!." ) ); + wxCHECK_RET( m_undoItem != NULL, + wxT( "Cannot swap undo item structures. Bad programmer!." ) ); + wxCHECK_RET( aItem->Type() == m_undoItem->Type(), + wxT( "Cannot swap undo item structures. Bad programmer!." ) ); + + aItem->SwapData( m_undoItem ); + SaveCopyInUndoList( aItem, UR_CHANGED ); + aItem->SwapData( m_undoItem ); +} + + +void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +{ + if( Kiface().IsSingle() ) + { + LIB_EDIT_FRAME* libeditFrame = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, false ); + if( libeditFrame && !libeditFrame->Close() ) // Can close component editor? + return; + + LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false ); + if( viewlibFrame && !viewlibFrame->Close() ) // Can close component viewer? + return; + + viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, false ); + if( viewlibFrame && !viewlibFrame->Close() ) // Can close modal component viewer? + return; + } + + SCH_SHEET_LIST sheetList; + + if( sheetList.IsModified() ) + { + wxString fileName = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + wxString msg = wxString::Format( _( + "Save the changes in\n'%s'\nbefore closing?"), + GetChars( fileName ) + ); + + int ii = DisplayExitDialog( this, msg ); + + switch( ii ) + { + case wxID_CANCEL: + aEvent.Veto(); + return; + + case wxID_NO: + break; + + case wxID_YES: + wxCommandEvent tmp( ID_SAVE_PROJECT ); + OnSaveProject( tmp ); + break; + } + } + + // Close the find dialog and preserve it's setting if it is displayed. + if( m_dlgFindReplace ) + { + m_findDialogPosition = m_dlgFindReplace->GetPosition(); + m_findDialogSize = m_dlgFindReplace->GetSize(); + m_findStringHistoryList = m_dlgFindReplace->GetFindEntries(); + m_replaceStringHistoryList = m_dlgFindReplace->GetReplaceEntries(); + m_dlgFindReplace->Destroy(); + m_dlgFindReplace = NULL; + } + + SCH_SCREENS screens; + wxFileName fn; + + for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() ) + { + fn = Prj().AbsolutePath( screen->GetFileName() ); + + // Auto save file name is the normal file name prepended with AUTOSAVE_PREFIX_FILENAME. + fn.SetName( AUTOSAVE_PREFIX_FILENAME + fn.GetName() ); + + if( fn.FileExists() && fn.IsFileWritable() ) + wxRemoveFile( fn.GetFullPath() ); + } + + sheetList.ClearModifyStatus(); + + wxString fileName = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + + if( !g_RootSheet->GetScreen()->GetFileName().IsEmpty() && + g_RootSheet->GetScreen()->GetDrawItems() != NULL ) + { + UpdateFileHistory( fileName ); + } + + g_RootSheet->GetScreen()->Clear(); + + // all sub sheets are deleted, only the main sheet is usable + m_CurrentSheet->Clear(); + + Destroy(); +} + + +double SCH_EDIT_FRAME::BestZoom() +{ + int dx, dy; + wxSize size; + + dx = GetScreen()->GetPageSettings().GetWidthIU(); + dy = GetScreen()->GetPageSettings().GetHeightIU(); + + size = m_canvas->GetClientSize(); + + // Reserve no margin because best zoom shows the full page + // and margins are already included in function that draws the sheet refernces + double margin_scale_factor = 1.0; + double zx =(double) dx / ( margin_scale_factor * (double)size.x ); + double zy = (double) dy / ( margin_scale_factor * (double)size.y ); + + double bestzoom = std::max( zx, zy ); + + SetScrollCenterPosition( wxPoint( dx / 2, dy / 2 ) ); + + return bestzoom; +} + + +wxString SCH_EDIT_FRAME::GetUniqueFilenameForCurrentSheet() +{ + wxFileName fn = GetScreen()->GetFileName(); + + // Name is - and has no extension. + // However if filename is too long name is - + + #define FN_LEN_MAX 80 // A reasonable value for the short filename len + + wxString filename = fn.GetName(); + wxString sheetFullName = m_CurrentSheet->PathHumanReadable(); + + // Remove the last '/' of the path human readable + // (and for the root sheet, make sheetFullName empty): + sheetFullName.RemoveLast(); + + sheetFullName.Trim( true ); + sheetFullName.Trim( false ); + + // Convert path human readable separator to '-' + sheetFullName.Replace( wxT( "/" ), wxT( "-" ) ); + + if( ( filename.Len() + sheetFullName.Len() ) < FN_LEN_MAX ) + filename += sheetFullName; + else + filename << wxT( "-" ) << GetScreen()->m_ScreenNumber; + + return filename; +} + + +void SCH_EDIT_FRAME::OnModify() +{ + GetScreen()->SetModify(); + GetScreen()->SetSave(); + + m_foundItems.SetForceSearch(); +} + + +void SCH_EDIT_FRAME::OnUpdateBlockSelected( wxUpdateUIEvent& event ) +{ + bool enable = ( GetScreen() && GetScreen()->m_BlockLocate.GetCommand() == BLOCK_MOVE ); + + event.Enable( enable ); +} + + +void SCH_EDIT_FRAME::OnUpdatePaste( wxUpdateUIEvent& event ) +{ + event.Enable( m_blockItems.GetCount() > 0 ); +} + + +void SCH_EDIT_FRAME::OnUpdateBusOrientation( wxUpdateUIEvent& aEvent ) +{ + wxString tool_tip = GetForceHVLines() ? + _( "Draw wires and buses in any direction" ) : + _( "Draw horizontal and vertical wires and buses only" ); + + aEvent.Check( GetForceHVLines() ); + m_optionsToolBar->SetToolShortHelp( ID_TB_OPTIONS_BUS_WIRES_ORIENT, tool_tip ); +} + + +void SCH_EDIT_FRAME::OnUpdateHiddenPins( wxUpdateUIEvent& aEvent ) +{ + wxString tool_tip = m_showAllPins ? _( "Do not show hidden pins" ) : + _( "Show hidden pins" ); + + aEvent.Check( m_showAllPins ); + m_optionsToolBar->SetToolShortHelp( ID_TB_OPTIONS_HIDDEN_PINS, tool_tip ); +} + + +void SCH_EDIT_FRAME::OnUpdateSave( wxUpdateUIEvent& aEvent ) +{ + SCH_SHEET_LIST sheetList; + + aEvent.Enable( sheetList.IsModified() ); +} + + +void SCH_EDIT_FRAME::OnUpdateSaveSheet( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( GetScreen()->IsModify() ); + +} + + +void SCH_EDIT_FRAME::OnUpdateHierarchySheet( wxUpdateUIEvent& aEvent ) +{ + aEvent.Enable( m_CurrentSheet->Last() != g_RootSheet ); +} + + +void SCH_EDIT_FRAME::OnAnnotate( wxCommandEvent& event ) +{ + InvokeDialogAnnotate( this ); +} + + +void SCH_EDIT_FRAME::OnErc( wxCommandEvent& event ) +{ + // See if it's already open... + wxWindow* erc = FindWindowById( ID_DIALOG_ERC, this ); + + if( erc ) + // Bring it to the top if already open. Dual monitor users need this. + erc->Raise(); + else + InvokeDialogERC( this ); +} + + +void SCH_EDIT_FRAME::OnCreateNetlist( wxCommandEvent& event ) +{ + int result; + + do + { + result = InvokeDialogNetList( this ); + + // If a plugin is removed or added, rebuild and reopen the new dialog + + } while( result == NET_PLUGIN_CHANGE ); +} + + +void SCH_EDIT_FRAME::OnCreateBillOfMaterials( wxCommandEvent& ) +{ + InvokeDialogCreateBOM( this ); +} + + +void SCH_EDIT_FRAME::OnFindItems( wxCommandEvent& aEvent ) +{ + wxCHECK_RET( m_findReplaceData != NULL, + wxT( "Forgot to create find/replace data. Bad Programmer!" ) ); + + if( m_dlgFindReplace ) + { + delete m_dlgFindReplace; + m_dlgFindReplace = NULL; + } + + // Verify the find dialog is not drawn off the visible display area in case the + // display configuration has changed since the last time the dialog position was + // saved. + wxRect displayRect = wxDisplay().GetGeometry(); + wxRect dialogRect = wxRect( m_findDialogPosition, m_findDialogSize ); + + wxPoint position = m_findDialogPosition; + + if( !displayRect.Contains( dialogRect ) ) + { + position = wxDefaultPosition; + } + + int style = 0; + + if( aEvent.GetId() == wxID_REPLACE ) + style = wxFR_REPLACEDIALOG; + + m_dlgFindReplace = new DIALOG_SCH_FIND( this, m_findReplaceData, position, m_findDialogSize, + style ); + + m_dlgFindReplace->SetFindEntries( m_findStringHistoryList ); + m_dlgFindReplace->SetReplaceEntries( m_replaceStringHistoryList ); + m_dlgFindReplace->Show( true ); +} + + +void SCH_EDIT_FRAME::OnFindDialogClose( wxFindDialogEvent& event ) +{ + // If the user dismissed the dialog with the mouse, this will send the cursor back + // to the last item found. + OnFindSchematicItem( event ); + + if( m_dlgFindReplace ) + { + m_findDialogPosition = m_dlgFindReplace->GetPosition(); + m_findDialogSize = m_dlgFindReplace->GetSize(); + m_findStringHistoryList = m_dlgFindReplace->GetFindEntries(); + m_replaceStringHistoryList = m_dlgFindReplace->GetReplaceEntries(); + m_dlgFindReplace->Destroy(); + m_dlgFindReplace = NULL; + } +} + + +void SCH_EDIT_FRAME::OnLoadFile( wxCommandEvent& event ) +{ + wxString fn = GetFileFromHistory( event.GetId(), _( "Schematic" ) ); + + if( fn.size() ) + OpenProjectFiles( std::vector( 1, fn ) ); +} + + +void SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile( wxCommandEvent& event ) +{ + LoadCmpToFootprintLinkFile(); + m_canvas->Refresh(); +} + + +void SCH_EDIT_FRAME::OnNewProject( wxCommandEvent& event ) +{ +// wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); + wxString pro_dir = m_mruPath; + + wxFileDialog dlg( this, _( "New Schematic" ), pro_dir, + wxEmptyString, SchematicFileWildcard, + wxFD_SAVE ); + + if( dlg.ShowModal() != wxID_CANCEL ) + { + // Enforce the extension, wxFileDialog is inept. + wxFileName create_me = dlg.GetPath(); + create_me.SetExt( SchematicFileExtension ); + + if( create_me.FileExists() ) + { + wxString msg = wxString::Format( _( + "Schematic file '%s' already exists, use Open instead" ), + GetChars( create_me.GetFullName() ) + ); + DisplayError( this, msg ); + return ; + } + + // OpenProjectFiles() requires absolute + wxASSERT_MSG( create_me.IsAbsolute(), wxT( "wxFileDialog returned non-absolute" ) ); + + OpenProjectFiles( std::vector( 1, create_me.GetFullPath() ), KICTL_CREATE ); + m_mruPath = create_me.GetPath(); + } +} + + +void SCH_EDIT_FRAME::OnLoadProject( wxCommandEvent& event ) +{ +// wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); + wxString pro_dir = m_mruPath; + + wxFileDialog dlg( this, _( "Open Schematic" ), pro_dir, + wxEmptyString, SchematicFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() != wxID_CANCEL ) + { + OpenProjectFiles( std::vector( 1, dlg.GetPath() ) ); + m_mruPath = Prj().GetProjectPath(); + } +} + + +void SCH_EDIT_FRAME::OnOpenPcbnew( wxCommandEvent& event ) +{ + wxFileName kicad_board = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + + if( kicad_board.IsOk() ) + { + kicad_board.SetExt( PcbFileExtension ); + wxFileName legacy_board( kicad_board ); + legacy_board.SetExt( LegacyPcbFileExtension ); + wxFileName& boardfn = ( !legacy_board.FileExists() || kicad_board.FileExists() ) ? + kicad_board : legacy_board; + + if( Kiface().IsSingle() ) + { + wxString filename = QuoteFullPath( boardfn ); + ExecuteFile( this, PCBNEW_EXE, filename ); + } + else + { + KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB, true ); + + // a pcb frame can be already existing, but not yet used. + // this is the case when running the footprint editor, or the footprint viewer first + // if the frame is not visible, the board is not yet loaded + if( !frame->IsVisible() ) + { + frame->OpenProjectFiles( std::vector( 1, boardfn.GetFullPath() ) ); + frame->Show( true ); + } + + // On Windows, Raise() does not bring the window on screen, when iconized + if( frame->IsIconized() ) + frame->Iconize( false ); + + frame->Raise(); + } + } + else + { + ExecuteFile( this, PCBNEW_EXE ); + } +} + + +void SCH_EDIT_FRAME::OnOpenPcbModuleEditor( wxCommandEvent& event ) +{ + wxFileName fn = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + + if( fn.IsOk() ) + { + KIWAY_PLAYER* fp_editor = Kiway().Player( FRAME_PCB_MODULE_EDITOR ); + + // On Windows, Raise() does not bring the window on screen, when iconized + if( fp_editor->IsIconized() ) + fp_editor->Iconize( false ); + + fp_editor->Show( true ); + fp_editor->Raise(); + } +} + + +void SCH_EDIT_FRAME::OnOpenCvpcb( wxCommandEvent& event ) +{ + wxFileName fn = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + + fn.SetExt( NetlistFileExtension ); + + if( prepareForNetlist() ) + { + KIWAY_PLAYER* player = Kiway().Player( FRAME_CVPCB, false ); // test open already. + + if( !player ) + { + player = Kiway().Player( FRAME_CVPCB, true ); + player->Show( true ); + // player->OpenProjectFiles( std::vector( 1, fn.GetFullPath() ) ); + } + + sendNetlist(); + + player->Raise(); + } +} + + +void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event ) +{ + SCH_COMPONENT* component = NULL; + + if( event.GetId() == ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP ) + { + // We want to edit a component with Libedit. + // we are here by a hot key, or by a popup menu + SCH_ITEM* item = GetScreen()->GetCurItem(); + + if( !item ) + { + // If we didn't get here by a hot key, then something has gone wrong. + if( event.GetInt() == 0 ) + return; + + EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) event.GetClientObject(); + + wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); + + // Set the locat filter, according to the edit command + const KICAD_T* filterList = SCH_COLLECTOR::ComponentsOnly; + item = LocateAndShowItem( data->GetPosition(), filterList, event.GetInt() ); + + // Exit if no item found at the current location or the item is already being edited. + if( (item == NULL) || (item->GetFlags() != 0) ) + return; + } + + + if( !item || (item->GetFlags() != 0) || ( item->Type() != SCH_COMPONENT_T ) ) + { + wxMessageBox( _( "Error: not a component or no component" ) ); + return; + } + + component = (SCH_COMPONENT*) item; + } + + LIB_EDIT_FRAME* libeditFrame = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, false ); + + if( !libeditFrame ) + { + libeditFrame = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, true ); + libeditFrame->Show( true ); + } + + libeditFrame->PushPreferences( m_canvas ); + + // On Windows, Raise() does not bring the window on screen, when iconized + if( libeditFrame->IsIconized() ) + libeditFrame->Iconize( false ); + + libeditFrame->Raise(); + + if( component ) + { + if( PART_LIBS* libs = Prj().SchLibs() ) + { + LIB_ALIAS* entry = libs->FindLibraryEntry( component->GetPartName() ); + + if( !entry ) // Should not occur + return; + + PART_LIB* library = entry->GetLib(); + + libeditFrame->LoadComponentAndSelectLib( entry, library ); + } + } +} + + +void SCH_EDIT_FRAME::OnRescueProject( wxCommandEvent& event ) +{ + RescueProject( true ); +} + + +void SCH_EDIT_FRAME::OnExit( wxCommandEvent& event ) +{ + Close( false ); +} + + +void SCH_EDIT_FRAME::OnPrint( wxCommandEvent& event ) +{ + InvokeDialogPrintUsingPrinter( this ); + + wxFileName fn = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); + + if( fn.GetName() != NAMELESS_PROJECT ) + { + // was: wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParametersList() ); + Prj().ConfigSave( Kiface().KifaceSearch(), GROUP_SCH_EDITOR, + GetProjectFileParametersList() ); + } +} + + +void SCH_EDIT_FRAME::PrintPage( wxDC* aDC, LSET aPrintMask, bool aPrintMirrorMode, + void* aData ) +{ + wxString fileName = Prj().AbsolutePath( GetScreen()->GetFileName() ); + + GetScreen()->Draw( m_canvas, aDC, GR_DEFAULT_DRAWMODE ); + DrawWorkSheet( aDC, GetScreen(), GetDefaultLineThickness(), IU_PER_MILS, fileName ); +} + + +void SCH_EDIT_FRAME::OnSelectItem( wxCommandEvent& aEvent ) +{ + int id = aEvent.GetId(); + int index = id - ID_SELECT_ITEM_START; + + if( (id >= ID_SELECT_ITEM_START && id <= ID_SELECT_ITEM_END) + && (index >= 0 && index < m_collectedItems.GetCount()) ) + { + SCH_ITEM* item = m_collectedItems[index]; + m_canvas->SetAbortRequest( false ); + GetScreen()->SetCurItem( item ); + } +} + + +bool SCH_EDIT_FRAME::isAutoSaveRequired() const +{ + // In case this event happens before g_RootSheet is initialized which does happen + // on mingw64 builds. + + if( g_RootSheet != NULL ) + { + SCH_SHEET_LIST sheetList; + + return sheetList.IsAutoSaveRequired(); + } + + return false; +} + + +void SCH_EDIT_FRAME::addCurrentItemToList( bool aRedraw ) +{ + SCH_SCREEN* screen = GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + wxCHECK_RET( item != NULL, wxT( "Cannot add current item to list." ) ); + + m_canvas->SetAutoPanRequest( false ); + + SCH_ITEM* undoItem = item; + + if( item->Type() == SCH_SHEET_PIN_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) item->GetParent(); + + wxCHECK_RET( (sheet != NULL) && (sheet->Type() == SCH_SHEET_T), + wxT( "Cannot place sheet pin in invalid schematic sheet object." ) ); + + undoItem = sheet; + } + + else if( item->Type() == SCH_FIELD_T ) + { + SCH_COMPONENT* cmp = (SCH_COMPONENT*) item->GetParent(); + + wxCHECK_RET( (cmp != NULL) && (cmp->Type() == SCH_COMPONENT_T), + wxT( "Cannot place field in invalid schematic component object." ) ); + + undoItem = cmp; + } + + if( item->IsNew() ) + { + if( item->Type() == SCH_SHEET_T ) + { + // Fix the size and position of the new sheet using the last values set by + // the m_mouseCaptureCallback function. + m_canvas->SetMouseCapture( NULL, NULL ); + + if( !EditSheet( (SCH_SHEET*)item, m_CurrentSheet ) ) + { + screen->SetCurItem( NULL ); + delete item; + + if( aRedraw ) + GetCanvas()->Refresh(); + + return; + } + + SetSheetNumberAndCount(); + } + + if( undoItem == item ) + { + if( !screen->CheckIfOnDrawList( item ) ) // don't want a loop! + screen->Append( item ); + + SetRepeatItem( item ); + + SaveCopyInUndoList( undoItem, UR_NEW ); + } + else + { + // Here, item is not a basic schematic item, but an item inside + // a parent basic schematic item, + // currently: sheet pin or component field. + // currently, only a sheet pin can be found as new item, + // because new component fields have a specific handling, and do not appears here + SaveCopyInUndoList( undoItem, UR_CHANGED ); + + if( item->Type() == SCH_SHEET_PIN_T ) + ( (SCH_SHEET*)undoItem )->AddPin( (SCH_SHEET_PIN*) item ); + else + wxLogMessage( wxT( "addCurrentItemToList: expected type = SCH_SHEET_PIN_T, actual type = %d" ), + item->Type() ); + } + } + else + { + SaveUndoItemInUndoList( undoItem ); + } + + item->ClearFlags(); + screen->SetModify(); + screen->SetCurItem( NULL ); + m_canvas->SetMouseCapture( NULL, NULL ); + m_canvas->EndMouseCapture(); + + if( item->IsConnectable() ) + screen->TestDanglingEnds(); + + if( aRedraw ) + GetCanvas()->Refresh(); +} + + +void SCH_EDIT_FRAME::UpdateTitle() +{ + wxString title; + + if( GetScreen()->GetFileName() == m_DefaultSchematicFileName ) + { + title.Printf( wxT( "Eeschema %s [%s]" ), GetChars( GetBuildVersion() ), + GetChars( GetScreen()->GetFileName() ) ); + } + else + { + wxString fileName = Prj().AbsolutePath( GetScreen()->GetFileName() ); + wxFileName fn = fileName; + + title.Printf( wxT( "[ %s %s] (%s)" ), + GetChars( fn.GetName() ), + GetChars( m_CurrentSheet->PathHumanReadable() ), + GetChars( fn.GetPath() ) ); + + if( fn.FileExists() ) + { + if( !fn.IsFileWritable() ) + title += _( " [Read Only]" ); + } + else + title += _( " [no file]" ); + } + + SetTitle( title ); +} + diff --git a/eeschema/schframe.h b/eeschema/schframe.h new file mode 100644 index 00000000..0db8ea82 --- /dev/null +++ b/eeschema/schframe.h @@ -0,0 +1,1351 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras wanadoo.fr + * Copyright (C) 2008-2015 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file wxEeschemaStruct.h + */ + +#ifndef WX_EESCHEMA_STRUCT_H +#define WX_EESCHEMA_STRUCT_H + +#include +#include +#include +#include +#include +#include +#include + + +class LIB_EDIT_FRAME; +class LIB_VIEW_FRAME; +class DRAWSEGMENT; +class SCH_ITEM; +class SCH_NO_CONNECT; +class EDA_ITEM; +class SCH_BUS_ENTRY_BASE; +class SCH_BUS_WIRE_ENTRY; +class SCH_BUS_BUS_ENTRY; +class SCH_GLOBALLABEL; +class SCH_TEXT; +class SCH_BITMAP; +class SCH_SHEET; +class SCH_SHEET_PATH; +class SCH_SHEET_PIN; +class SCH_COMPONENT; +class SCH_FIELD; +class LIB_PIN; +class SCH_JUNCTION; +class DIALOG_SCH_FIND; +class wxFindDialogEvent; +class wxFindReplaceData; +class SCHLIB_FILTER; + + +/// enum used in RotationMiroir() +enum COMPONENT_ORIENTATION_T { + CMP_NORMAL, // Normal orientation, no rotation or mirror + CMP_ROTATE_CLOCKWISE, // Rotate -90 + CMP_ROTATE_COUNTERCLOCKWISE, // Rotate +90 + CMP_ORIENT_0, // No rotation and no mirror id CMP_NORMAL + CMP_ORIENT_90, // Rotate 90, no mirror + CMP_ORIENT_180, // Rotate 180, no mirror + CMP_ORIENT_270, // Rotate -90, no mirror + CMP_MIRROR_X = 0x100, // Mirror around X axis + CMP_MIRROR_Y = 0x200 // Mirror around Y axis +}; + + +/** Schematic annotation order options. */ +enum ANNOTATE_ORDER_T { + SORT_BY_X_POSITION, ///< Annotate by X position from left to right. + SORT_BY_Y_POSITION, ///< Annotate by Y position from top to bottom. + UNSORTED, ///< Annotate by position of component in the schematic sheet + ///< object list. +}; + + +/** Schematic annotation type options. */ +enum ANNOTATE_OPTION_T { + INCREMENTAL_BY_REF, ///< Annotate incrementally using the first free reference number. + SHEET_NUMBER_X_100, ///< Annotate using the first free reference number starting at + ///< the sheet number * 100. + SHEET_NUMBER_X_1000, ///< Annotate using the first free reference number starting at + ///< the sheet number * 1000. +}; + + +/// Schematic search type used by the socket link with Pcbnew +enum SCH_SEARCH_T { + FIND_COMPONENT_ONLY, ///< Find a component in the schematic. + FIND_PIN, ///< Find a component pin in the schematic. + FIND_REFERENCE, ///< Find an item by it's reference designator. + FIND_VALUE, ///< Find an item by it's value field. + FIND_FIELD ///< Find a component field. +}; + + +#define SCH_EDIT_FRAME_NAME wxT( "SchematicFrame" ) + +/** + * Schematic editor (Eeschema) main window. + */ +class SCH_EDIT_FRAME : public SCH_BASE_FRAME +{ +private: + SCH_SHEET_PATH* m_CurrentSheet; ///< which sheet we are presently working on. + wxString m_DefaultSchematicFileName; + + PARAM_CFG_ARRAY m_projectFileParams; + PARAM_CFG_ARRAY m_configSettings; + wxPageSetupDialogData m_pageSetupData; + wxFindReplaceData* m_findReplaceData; + wxPoint m_previewPosition; + wxSize m_previewSize; + wxPoint m_printDialogPosition; + wxSize m_printDialogSize; + bool m_printMonochrome; ///< Print monochrome instead of grey scale. + bool m_printSheetReference; + DIALOG_SCH_FIND* m_dlgFindReplace; + wxPoint m_findDialogPosition; + wxSize m_findDialogSize; + wxArrayString m_findStringHistoryList; + wxArrayString m_replaceStringHistoryList; + BLOCK_SELECTOR m_blockItems; ///< List of selected items. + SCH_ITEM* m_item_to_repeat; ///< Last item to insert by the repeat command. + int m_repeatLabelDelta; ///< Repeat label number increment step. + SCH_COLLECTOR m_collectedItems; ///< List of collected items. + SCH_FIND_COLLECTOR m_foundItems; ///< List of find/replace items. + SCH_ITEM* m_undoItem; ///< Copy of the current item being edited. + wxString m_simulatorCommand; ///< Command line used to call the circuit + ///< simulator (gnucap, spice, ...) + wxString m_netListerCommand; ///< Command line to call a custom net list + ///< generator. + + bool m_forceHVLines; ///< force H or V directions for wires, bus, line + + /// An index to the last find item in the found items list #m_foundItems. + int m_foundItemIndex; + + /// Flag to indicate show hidden pins. + bool m_showAllPins; + + /// The name of the destination directory to use when generating plot files. + wxString m_plotDirectoryName; + + /// The name of the format to use when generating a net list. + wxString m_netListFormat; + + /// Add X prefix to component references when generating spice net lists. + bool m_spiceNetlistAddReferencePrefix; + + /// Use netcodes (net number) as net names when generating spice net lists. + bool m_spiceNetlistUseNetcodeAsNetname; + + /* these are PROJECT specific, not schematic editor specific + wxString m_userLibraryPath; + wxArrayString m_componentLibFiles; + */ + + static int m_lastSheetPinType; ///< Last sheet pin type. + static wxSize m_lastSheetPinTextSize; ///< Last sheet pin text size. + static wxPoint m_lastSheetPinPosition; ///< Last sheet pin position. + +protected: + TEMPLATES m_TemplateFieldNames; + + /** + * Initializing accessor for the pin text size + */ + const wxSize &GetLastSheetPinTextSize(); + + /** + * Function doAutoSave + * saves the schematic files that have been modified and not yet saved. + * + * @return true if the auto save was successful otherwise false. + */ + virtual bool doAutoSave(); + + /** + * Function autoSaveRequired + * returns true if the schematic has been modified. + */ + virtual bool isAutoSaveRequired() const; + + /** + * Function addCurrentItemToList + * adds the item currently being edited to the schematic and adds the changes to + * the undo/redo container. + * + * @param aRedraw = true (default) to redrw -the screen after adding the item. + */ + void addCurrentItemToList( bool aRedraw = true ); + + void updateFindReplaceView( wxFindDialogEvent& aEvent ); + + void backAnnotateFootprints( const std::string& aChangedSetOfReferences ) + throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function prepareForNetlist + * verifies that annotation is complete so that a proper netlist is even + * possible. If not, asks the user if annotation should be done. + * @return bool - true if annotation is complete, else false. + */ + bool prepareForNetlist(); + + /** + * Function sendNetlist + * sends the kicad netlist over to CVPCB. + */ + void sendNetlist(); + +public: + SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); + ~SCH_EDIT_FRAME(); + + SCH_SCREEN* GetScreen() const; // overload SCH_BASE_FRAME + + void OnCloseWindow( wxCloseEvent& Event ); + + bool GetForceHVLines() const { return m_forceHVLines; } + void SetForceHVLines( bool aForceHVdirection ) { m_forceHVLines = aForceHVdirection; } + + bool GetShowAllPins() const { return m_showAllPins; } + + void SetShowAllPins( bool aEnable ) { m_showAllPins = aEnable; } + + const wxString GetNetListFormatName() const { return m_netListFormat; } + + void SetNetListFormatName( const wxString& aFormat ) { m_netListFormat = aFormat; } + + bool GetSpiceAddReferencePrefix() const { return m_spiceNetlistAddReferencePrefix; } + + void SetSpiceAddReferencePrefix( bool aEnable ) { m_spiceNetlistAddReferencePrefix = aEnable; } + + bool GetSpiceUseNetcodeAsNetname() const { return m_spiceNetlistUseNetcodeAsNetname; } + + void SetSpiceUseNetcodeAsNetname( bool aEnable ) { m_spiceNetlistUseNetcodeAsNetname = aEnable; } + + /* These are PROJECT specific, not schematic editor specific + wxString GetUserLibraryPath() const { return m_userLibraryPath; } + void SetUserLibraryPath( const wxString& aPath ) { m_userLibraryPath = aPath; } + const wxArrayString& GetComponentLibraries() const { return m_componentLibFiles; } + void SetComponentLibraries( const wxArrayString& aList ) { m_componentLibFiles = aList; } + */ + + /// accessor to the destination directory to use when generating plot files. + const wxString& GetPlotDirectoryName() const { return m_plotDirectoryName; } + void SetPlotDirectoryName( const wxString& aDirName ) { m_plotDirectoryName = aDirName; } + + void Process_Special_Functions( wxCommandEvent& event ); + void OnColorConfig( wxCommandEvent& aEvent ); + void Process_Config( wxCommandEvent& event ); + void OnSelectTool( wxCommandEvent& aEvent ); + + bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); + + /** + * Function GetProjectFileParametersList + * returns the project file parameter list for Eeschema. + * + *

      + * Populate the project file parameter array specific to Eeschema if it hasn't + * already been populated and return a reference to the array to the caller. + *

      + */ + PARAM_CFG_ARRAY& GetProjectFileParametersList(); + + /** + * Function SaveProjectSettings + * saves changes to the project settings to the project (.pro) file. + * @param aAskForSave = true to open a dialog before saving the settings + */ + void SaveProjectSettings( bool aAskForSave ); + + /** + * Function LoadProjectFile + * loads the KiCad project file (*.pro) settings specific to Eeschema. + * + * @return True if the project file was loaded correctly. + */ + bool LoadProjectFile(); + + /** + * Function GetDefaultFieldName + * returns a default symbol field name for field \a aFieldNdx for all components. + * These field names are not modifiable, but template field names are. + * @param aFieldNdx The field number index + */ + static wxString GetDefaultFieldName( int aFieldNdx ); + + /** + * Function AddTemplateFieldName + * inserts or appends a wanted symbol field name into the field names + * template. Should be used for any symbol property editor. If the name + * already exists, it overwrites the same name. + * + * @param aFieldName is a full description of the wanted field, and it must not match + * any of the default field names. + * @return int - the index within the config container at which aFieldName was + * added, or -1 if the name is illegal because it matches a default field name. + */ + int AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName ) + { + return m_TemplateFieldNames.AddTemplateFieldName( aFieldName ); + } + + + /** + * Function GetTemplateFieldName + * returns a template field names list for read only access. + */ + const TEMPLATE_FIELDNAMES& GetTemplateFieldNames() + { + return m_TemplateFieldNames.GetTemplateFieldNames(); + } + + + /** + * Function GetTemplates + * returns the field names template for read only access. + */ + const TEMPLATES& GetTemplates() + { + return m_TemplateFieldNames; + } + + /** + * Function DeleteAllTemplateFieldNames + * removes all template field names. + */ + void DeleteAllTemplateFieldNames() + { + m_TemplateFieldNames.DeleteAllTemplateFieldNames(); + } + + /** + * Function GetConfigurationSettings + * returns the Eeschema applications settings. + *

      + * This replaces the old statically define list that had the project file settings and + * the application settings mixed together. This was confusing and caused some settings + * to get saved and loaded incorrectly. Currently, only the settings that are needed at + * start up by the main window are defined here. There are other locally used settings + * scattered throughout the Eeschema source code. If you need to define a configuration + * setting that need to be loaded at run time, this is the place to define it. + *

      + */ + PARAM_CFG_ARRAY& GetConfigurationSettings(); + + void LoadSettings( wxConfigBase* aCfg ); + void SaveSettings( wxConfigBase* aCfg ); + + void RedrawActiveWindow( wxDC* DC, bool EraseBg ); + + void CreateScreens(); + void ReCreateHToolbar(); + void ReCreateVToolbar(); + void ReCreateOptToolbar(); + void ReCreateMenuBar(); + + ///> @copydoc EDA_DRAW_FRAME::GetHotKeyDescription() + EDA_HOTKEY* GetHotKeyDescription( int aCommand ) const; + + bool OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem = NULL ); + + /** + * Function OnModify + * Must be called after a schematic change + * in order to set the "modify" flag of the current screen + * and update the date in frame reference + */ + void OnModify(); + + virtual wxString GetScreenDesc() const; + + void InstallConfigFrame( wxCommandEvent& event ); + + /** + * Execute a remote command send by Pcbnew via a socket, + * port KICAD_SCH_PORT_SERVICE_NUMBER (currently 4243) + * this is a virtual function called by EDA_DRAW_FRAME::OnSockRequest(). + * @param cmdline = received command from socket + */ + virtual void ExecuteRemoteCommand( const char* cmdline ); + + void KiwayMailIn( KIWAY_EXPRESS& aEvent ); // override virtual from KIWAY_PLAYER + + void OnLeftClick( wxDC* aDC, const wxPoint& aPosition ); + void OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ); + bool OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu ); + void OnSelectOptionToolbar( wxCommandEvent& event ); + double BestZoom(); + + /** + * Function LocateAndShowItem + * checks the schematic at \a aPosition in logical (drawing) units for a item + * matching the types in \a aFilterList. + *

      + * The search is first performed at the nearest grid position to \a aPosition. If no + * item if found on grid, then \a aPosition is tested for any items. If the item found + * can be cross probed, a message is send to Pcbnew and the selected item is highlighted + * in PCB editor. + *

      + * @param aPosition The wxPoint on the schematic to search. + * @param aFilterList A list of #KICAD_T types to to filter. + * @param aHotKeyCommandId A hot key command ID for performing additional tests when + * multiple items are found at \a aPosition. + * @return A SCH_ITEM pointer of the item found or NULL if no item found + */ + SCH_ITEM* LocateAndShowItem( const wxPoint& aPosition, + const KICAD_T aFilterList[] = SCH_COLLECTOR::AllItems, + int aHotKeyCommandId = 0 ); + + /** + * Function LocateItem + * checks for items at \a aPosition matching the types in \a aFilterList. + *

      + * If multiple items are located at \a aPosition, a context menu is displayed to clarify + * which item the user intended to select. If the user aborts the context menu, NULL is + * returned and the abort request flag will be set to true. Make sure to clear this flag + * before attempting to display any other context menus. + *

      + * + * @param aPosition The wxPoint location where to search. + * @param aFilterList A list of #KICAD_T types to to filter. + * @param aHotKeyCommandId A hot key command ID for performing additional tests when + * multiple items are found at \a aPosition. + * @return The SCH_ITEM pointer of the item found or NULL if no item found. + */ + SCH_ITEM* LocateItem( const wxPoint& aPosition, + const KICAD_T aFilterList[] = SCH_COLLECTOR::AllItems, + int aHotKeyCommandId = 0 ); + + /** + * Function DeleteItemAtCrossHair + * delete the item found under the cross hair. If multiple items are found at the + * cross hair position, a context menu is displayed to clarify which item to delete. + * See LocateItem() for more information on locating multiple items. + * + * @param aDC The device context to update if and item is deleted. + * @return True if an item was deleted. + */ + bool DeleteItemAtCrossHair( wxDC* aDC ); + + /** + * Function FindComponentAndItem + * finds a component in the schematic and an item in this component. + * @param aReference The component reference designator to find. + * @param aSearchHierarchy If false, search the current sheet only. Otherwise, + * the entire hierarchy + * @param aSearchType A #SCH_SEARCH_T value used to determine what to search for. + * @param aSearchText The text to search for, either in value, reference or elsewhere. + * @param aWarpMouse If true, then move the mouse cursor to the item. + */ + SCH_ITEM* FindComponentAndItem( const wxString& aReference, + bool aSearchHierarchy, + SCH_SEARCH_T aSearchType, + const wxString& aSearchText, + bool aWarpMouse ); + + /** + * Function SendMessageToPcbnew + * send a remote to Pcbnew via a socket connection. + * @param objectToSync Item to be located on board (footprint, pad or text) + * @param LibItem Component in library if objectToSync is a sub item of a component + *

      + * Commands are + * $PART: reference put cursor on footprint anchor + * $PIN: number $PART: reference put cursor on the footprint pad + *

      + */ + void SendMessageToPCBNEW( EDA_ITEM* objectToSync, SCH_COMPONENT* LibItem ); + + /** + * BuildNetListBase + * netlist generation: + * Creates a flat list which stores all connected objects, and mainly + * pins and labels. + * @return NETLIST_OBJECT_LIST* - caller owns the object. + */ + NETLIST_OBJECT_LIST* BuildNetListBase(); + + /** + * Function CreateNetlist + *
        + *
      • test for some issues (missing or duplicate references and sheet names) + *
      • build netlist info + *
      • create the netlist file (different formats) + *
      + * @param aFormat = netlist format (NET_TYPE_PCBNEW ...) + * @param aFullFileName = full netlist file name + * @param aNetlistOptions = netlist options using OR'ed bits. + *

      + * For SPICE netlist only: + * if NET_USE_NETNAMES is set, use net names from labels in schematic + * else use net numbers (net codes) + * if NET_USE_X_PREFIX is set : change "U" and "IC" refernce prefix to "X" + *

      + * @param aReporter = a REPORTER to report error messages, + * mainly if a command line must be run (can be NULL + * @return true if success. + */ + bool CreateNetlist( int aFormat, + const wxString& aFullFileName, + unsigned aNetlistOptions, + REPORTER* aReporter = NULL ); + + /** + * Function WriteNetListFile + * Create the netlist file. Netlist info must be existing + * (BuildNetListBase() creates this info) + * @param aConnectedItemsList = the initialized list of connected items, take ownership. + * @param aFormat = netlist format (NET_TYPE_PCBNEW ...) + * @param aFullFileName = full netlist file name + * @param aNetlistOptions = netlist options using OR'ed bits. + *

      + * For SPICE netlist only: + * if NET_USE_NETNAMES is set, use net names from labels in schematic + * else use net numbers (net codes) + * if NET_USE_X_PREFIX is set : change "U" and "IC" refernce prefix to "X" + *

      + * @param aReporter = a REPORTER to report error messages, + * mainly if a command line must be run (can be NULL + * @return true if success. + */ + bool WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList, + int aFormat, + const wxString& aFullFileName, + unsigned aNetlistOptions, + REPORTER* aReporter = NULL ); + + /** + * Function DeleteAnnotation + * clears the current component annotation. + * @param aCurrentSheetOnly Clear only the annotation for the current sheet if true. + * Otherwise clear the entire schematic annotation. + */ + void DeleteAnnotation( bool aCurrentSheetOnly ); + + /** + * Function AnnotateComponents + * + * annotates the components in the schematic that are not currently annotated. + * + * @param aAnnotateSchematic Annotate the entire schematic if true. Otherwise annotate + * the current sheet only. + * @param aSortOption Define the annotation order. See #ANNOTATE_ORDER_T. + * @param aAlgoOption Define the annotation style. See #ANNOTATE_OPTION_T. + * @param aResetAnnotation Clear any previous annotation if true. Otherwise, keep the + * existing component annotation. + * @param aRepairTimestamps Test for and repair any duplicate time stamps if true. + * Otherwise, keep the existing time stamps. This option + * could change previous annotation because time stamps are + * used to handle annotation in complex hierarchies. + * @param aLockUnits When both aLockUnits and aResetAnnotation are true, all unit + * associations should be kept when reannotating. That is, if + * two components were R8A and R8B, they may become R3A and R3B, + * but not R3A and R3C or R3C and R4D. + * When aResetAnnotation is true but aLockUnits is false, the + * usual behavior of annotating each part individually is + * performed. + * When aResetAnnotation is false, this option has no effect. + * + * When the sheet number is used in annotation, each sheet annotation starts from sheet + * number * 100. In other words the first sheet uses 100 to 199, the second sheet uses + * 200 to 299, and so on. + */ + void AnnotateComponents( bool aAnnotateSchematic, ANNOTATE_ORDER_T aSortOption, + ANNOTATE_OPTION_T aAlgoOption, bool aResetAnnotation, + bool aRepairTimestamps, bool aLockUnits ); + + /** + * Function CheckAnnotate + * checks for annotation errors. + * + *

      + * The following list of items are checked: + *

        + *
      • Components that are not annotated. + *
      • Duplicate component references. + *
      • Multiple part per package components where the part\n + * number is greater number of parts in the package. + *
      • Multiple part per package components where the reference\n + * designator is different between parts. + *
      + *

      + * + * @return Number of annotation errors found. + * @param aMessageList A wxArrayString to store error messages. + * @param aOneSheetOnly Check the current sheet only if true. Otherwise check + * the entire schematic. + */ + int CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly ); + + // Functions used for hierarchy handling + SCH_SHEET_PATH& GetCurrentSheet(); + + void SetCurrentSheet( const SCH_SHEET_PATH& aSheet ); + + /** + * Function DisplayCurrentSheet + * draws the current sheet on the display. + */ + void DisplayCurrentSheet(); + + /** + * Function GetUniqueFilenameForCurrentSheet + * @return a filename that can be used in plot and print functions + * for the current screen and sheet path. + * This filename is unique and must be used instead of the screen filename + * (or screen filename) when one must creates file for each sheet in the + * hierarchy. because in complex hierarchies a sheet and a SCH_SCREEN is + * used more than once + * Name is <root sheet filename>-<sheet path> and has no extension. + * However if filename is too long name is <sheet filename>-<sheet number> + */ + wxString GetUniqueFilenameForCurrentSheet(); + + /** + * Function SetSheetNumberAndCount + * Set the m_ScreenNumber and m_NumberOfScreens members for screens + * must be called after a delete or add sheet command, and when entering + * a sheet + */ + void SetSheetNumberAndCount(); + + /** + * Show the print dialog + */ + void OnPrint( wxCommandEvent& event ); + + wxPageSetupDialogData& GetPageSetupData() { return m_pageSetupData; } + + void SetPreviewPosition( const wxPoint& aPoint ) { m_previewPosition = aPoint; } + void SetPreviewSize( const wxSize& aSize ) { m_previewSize = aSize; } + const wxPoint& GetPreviewPosition() { return m_previewPosition; } + const wxSize& GetPreviewSize() { return m_previewSize; } + + void SetPrintDialogPosition( const wxPoint& aPoint ) + { + m_printDialogPosition = aPoint; + } + + + void SetPrintDialogSize( const wxSize& aSize ) { m_printDialogSize = aSize; } + const wxPoint& GetPrintDialogPosition() { return m_printDialogPosition; } + const wxSize& GetPrintDialogSize() { return m_printDialogSize; } + + bool GetPrintMonochrome() { return m_printMonochrome; } + void SetPrintMonochrome( bool aMonochrome ) { m_printMonochrome = aMonochrome; } + bool GetPrintSheetReference() { return m_printSheetReference; } + void SetPrintSheetReference( bool aShow ) { m_printSheetReference = aShow; } + + // Plot functions: +// void ToPostProcess( wxCommandEvent& event ); + void PlotSchematic( wxCommandEvent& event ); + + // read and save files + void Save_File( wxCommandEvent& event ); + + /** + * Function OnSaveProject + * is the command event handler to save the entire project and create a component library + * archive. + * + * The component library archive name is <root_name>-cache.lib + */ + void OnSaveProject( wxCommandEvent& aEvent ); + + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl = 0 ); // virtual from KIWAY_PLAYER + + /** + * Function AppendOneEEProject + * read an entire project and loads it into the schematic editor *without* + * replacing the existing contents. + * @return True if the project was imported properly. + */ + bool AppendOneEEProject(); + + /** + * Function LoadOneEEFile + * loads the schematic (.sch) file \a aFullFileName into \a aScreen. + * + * @param aScreen Pointer to the associated SCH_SCREEN object in which to load + * \a aFullFileName. + * @param aFullFileName A reference to a wxString object containing the absolute path + * and file name to load. + * @param append True if loaded file is being appended to the currently open file instead + * of replacing it. + * @return True if \a aFullFileName has been loaded (at least partially.) + */ + bool LoadOneEEFile( SCH_SCREEN* aScreen, const wxString& aFullFileName, bool append = false ); + + /** + * Function ReadCmpToFootprintLinkFile + * Loads a .cmp file from CvPcb and update the footprin field + * of components + * Prepares parameters and calls ProcessCmpToFootprintLinkFile + * to actually read the file and update Fp fields + */ + bool LoadCmpToFootprintLinkFile(); + + /** + * Function ProcessStuffFile + * gets footprint info from each line in the Stuff File by Ref Desg + * + * Read a Cmp To Footprint Link file created by CvPcb (the .cmp file). + * That file has lines like: + * BeginCmp + * TimeStamp = /32307DE2/AA450F67; + * Reference = C1; + * ValeurCmp = 47uF; + * IdModule = CP6; + * EndCmp + * + * @param aFullFilename = the full filename to read + * @param aForceVisibilityState = Set to true to change the footprint field visibility + * state to \a aVisibilityState. False retains the + * current footprint field visibility state. + * @param aVisibilityState True to show the footprint field or false to hide the footprint + * field if \a aForceVisibilityState is true. + * @return bool = true if success. + */ + bool ProcessCmpToFootprintLinkFile( const wxString& aFullFilename, + bool aForceVisibilityState, + bool aVisibilityState ); + + /** + * Function SaveEEFile + * saves \a aScreen to a schematic file. + * + * @param aScreen A pointer to the SCH_SCREEN object to save. A NULL pointer saves + * the current screen. + * @param aSaveUnderNewName Controls how the file is to be saved;: using previous name + * or under a new name . + * @param aCreateBackupFile Creates a back of the file associated with \a aScreen + * if true. + * Helper definitions #CREATE_BACKUP_FILE and + * #NO_BACKUP_FILE are defined for improved code readability. + * @return True if the file has been saved. + */ + bool SaveEEFile( SCH_SCREEN* aScreen, + bool aSaveUnderNewName = false, + bool aCreateBackupFile = CREATE_BACKUP_FILE ); + + // General search: + + bool IsSearchCacheObsolete( const SCH_FIND_REPLACE_DATA& aSearchCriteria ); + + +private: + + /** + * Function OnMoveItem + * handles the #ID_SCH_MOVE_ITEM event used to move schematic itams. + */ + void OnMoveItem( wxCommandEvent& aEvent ); + + /** + * Function OnRotate + * handles the #ID_SCH_ROTATE_CLOCKWISE and #ID_SCH_ROTATE_COUNTERCLOCKWISE events + * used to rotate schematic itams and blocks. + */ + void OnRotate( wxCommandEvent& aEvent ); + + /** + * Function OnEditItem + * handles the #ID_SCH_EDIT_ITEM event used to edit schematic itams. + */ + void OnEditItem( wxCommandEvent& aEvent ); + + /** + * Function OnDragItem + * handles the #ID_SCH_DRAG_ITEM event used to drag schematic itams. + */ + void OnDragItem( wxCommandEvent& aEvent ); + + /** + * Function OnOrient + * handles the #ID_SCH_MIRROR_X, #ID_SCH_MIRROR_Y, and #ID_SCH_ORIENT_NORMAL events + * used to orient schematic itams and blocks. + */ + void OnOrient( wxCommandEvent& aEvent ); + + void OnExit( wxCommandEvent& event ); + void OnAnnotate( wxCommandEvent& event ); + void OnErc( wxCommandEvent& event ); + void OnCreateNetlist( wxCommandEvent& event ); + void OnCreateBillOfMaterials( wxCommandEvent& event ); + void OnFindItems( wxCommandEvent& event ); + void OnFindDialogClose( wxFindDialogEvent& event ); + void OnFindDrcMarker( wxFindDialogEvent& event ); + void OnFindCompnentInLib( wxFindDialogEvent& event ); + + /** + * Function OnFindSchematicItem + * finds an item in the schematic matching the search criteria in \a aEvent. + * + * @param aEvent - Find dialog event containing the find parameters. + */ + void OnFindSchematicItem( wxFindDialogEvent& aEvent ); + + /** + * Function OnReplace + * performs a search and replace of text in an item in the schematic matching the + * search and replace criteria in \a aEvent. + * + * @param aEvent - Find dialog event containing the search and replace parameters. + */ + void OnFindReplace( wxFindDialogEvent& aEvent ); + + void OnLoadFile( wxCommandEvent& event ); + void OnLoadCmpToFootprintLinkFile( wxCommandEvent& event ); + void OnNewProject( wxCommandEvent& event ); + void OnLoadProject( wxCommandEvent& event ); + void OnAppendProject( wxCommandEvent& event ); + void OnOpenPcbnew( wxCommandEvent& event ); + void OnOpenPcbModuleEditor( wxCommandEvent& event ); + void OnOpenCvpcb( wxCommandEvent& event ); + void OnOpenLibraryEditor( wxCommandEvent& event ); + void OnRescueProject( wxCommandEvent& event ); + void OnPreferencesOptions( wxCommandEvent& event ); + void OnCancelCurrentCommand( wxCommandEvent& aEvent ); + + void OnSelectItem( wxCommandEvent& aEvent ); + + /** + * Function OnCopySchematicItemRequest + * is the command event handler for duplicating the item at the current location. + */ + void OnCopySchematicItemRequest( wxCommandEvent& event ); + + /* User interface update event handlers. */ + void OnUpdateBlockSelected( wxUpdateUIEvent& event ); + void OnUpdatePaste( wxUpdateUIEvent& event ); + void OnUpdateHiddenPins( wxUpdateUIEvent& event ); + void OnUpdateBusOrientation( wxUpdateUIEvent& event ); + void OnUpdateSelectTool( wxUpdateUIEvent& aEvent ); + void OnUpdateSave( wxUpdateUIEvent& aEvent ); + void OnUpdateSaveSheet( wxUpdateUIEvent& aEvent ); + void OnUpdateHierarchySheet( wxUpdateUIEvent& aEvent ); + + /** + * Function UpdateTitle + * sets the main window title bar text. + *

      + * If file name defined by SCH_SCREEN::m_FileName is not set, the title is set to the + * application name appended with no file. + * Otherwise, the title is set to the hierarchical sheet path and the full file name, + * and read only is appended to the title if the user does not have write + * access to the file. + *

      + */ + void UpdateTitle(); + + // Bus Entry + SCH_BUS_WIRE_ENTRY* CreateBusWireEntry(); + SCH_BUS_BUS_ENTRY* CreateBusBusEntry(); + void SetBusEntryShape( wxDC* DC, SCH_BUS_ENTRY_BASE* BusEntry, char entry_shape ); + + /** + * Function AddNoConnect + * add a no connect item to the current schematic sheet at \a aPosition. + * @param aDC The device context to draw the no connect to. + * @param aPosition The position in logical (drawing) units to add the no connect. + * @return The no connect item added. + */ + SCH_NO_CONNECT* AddNoConnect( wxDC* aDC, const wxPoint& aPosition ); + + /** + * Function AddJunction + * adds a new junction at \a aPosition. + */ + SCH_JUNCTION* AddJunction( wxDC* aDC, const wxPoint& aPosition, bool aPutInUndoList = false ); + + /** + * Function PrepareMoveItem + * start moving \a aItem using the mouse. + * + * @param aItem A pointer to an SCH_ITEM to move. + * @param aDC The device context to draw \a aItem. + */ + void PrepareMoveItem( SCH_ITEM* aItem, wxDC* aDC ); + + // Text, label, glabel + SCH_TEXT* CreateNewText( wxDC* aDC, int aType ); + void EditSchematicText( SCH_TEXT* TextStruct ); + void ChangeTextOrient( SCH_TEXT* aTextItem, wxDC* aDC ); + + /** + * Function OnCovertTextType + * is a command event handler to change a text type to an other one. The new text, + * label, hierarchical label, or global label is created from the old text and the + * old text is deleted. + */ + void OnConvertTextType( wxCommandEvent& aEvent ); + + /** + * Function BeginSegment + * creates a new segment ( WIRE, BUS ) or terminates the current segment in progress. + * + * If the end of the current segment is on an other segment, place a junction if needed + * and terminates the command. If the end of the current segment is on a pin, terminate + * the command. In all other cases starts a new segment. + */ + void BeginSegment( wxDC* DC, int type ); + + /** + * Function EndSegment + * called to terminate a bus, wire, or line creation + */ + void EndSegment( wxDC* DC ); + + /** + * Function DeleteCurrentSegment + * erases the last segment at the current mouse position. + */ + void DeleteCurrentSegment( wxDC* DC ); + void DeleteConnection( bool DeleteFullConnection ); + + // graphic lines + void Edge( DRAWSEGMENT* Segment, wxDC* DC ); + void SetNewWidth( DRAWSEGMENT* DrawSegm, wxDC* DC ); + void Layer( DRAWSEGMENT* Segment, wxDC* DC ); + DRAWSEGMENT* Begin_Edge( DRAWSEGMENT* Segment, wxDC* DC ); + + // Images: + SCH_BITMAP* CreateNewImage( wxDC* aDC ); + void MoveImage( SCH_BITMAP* aItem, wxDC* aDC ); + void RotateImage( SCH_BITMAP* aItem ); + /** + * Function MirrorImage + * Mirror a bitmap + * @param aItem = the SCH_BITMAP item to mirror + * @param Is_X_axis = true to mirror relative to Horizontal axis + * false to mirror relative to vertical axis + */ + void MirrorImage( SCH_BITMAP* aItem, bool Is_X_axis ); + void EditImage( SCH_BITMAP* aItem ); + + // Hierarchical Sheet & PinSheet + void InstallHierarchyFrame( wxPoint& pos ); + SCH_SHEET* CreateSheet( wxDC* DC ); + void ReSizeSheet( SCH_SHEET* Sheet, wxDC* DC ); + + /** + * Rotate a sheet on itself. Sheets do not have a anchor point. + * Because rotating it from its origin or its end is not friendly, + * Rotation is made around its centre + * @param aSheet the hierarchical sheet to rotate + * @param aRotCCW = true to rotate CCW, false to rotate CW + */ + void RotateHierarchicalSheet( SCH_SHEET* aSheet, bool aRotCCW ); + + /** + * Function MirrorSheet + * Mirror a hierarchical sheet + * Mirroring is made around its centre + * @param aSheet = the SCH_SHEET to mirror + * @param aFromXaxis = true to mirror relative to Horizontal axis + * false to mirror relative to vertical axis + */ + void MirrorSheet( SCH_SHEET* aSheet, bool aFromXaxis ); + + /// Loads the cache library associated to the aFileName + bool LoadCacheLibrary( const wxString& aFileName ); + +public: + /** + * Function EditSheet + * is used to edit an existing sheet or add a new sheet to the schematic. + *

      + * When \a aSheet is a new sheet: + *

        + *
      • and the file name already exists in the schematic hierarchy, the screen associated + * with the sheet found in the hierarchy is associated with \a aSheet.
      • + *
      • and the file name already exists on the system, then \a aSheet is loaded with the + * existing file.
      • + *
      • and the file name does not exist in the schematic hierarchy or on the file system, + * then a new screen is created and associated with \a aSheet.
      • + *

      + * When \a aSheet is an existing sheet: + *

        + *
      • and the file name already exists in the schematic hierarchy, the current associated + * screen is replace by the one found in the hierarchy.
      • + *
      • and the file name already exists on the system, the current associated screen file + * name is changed and the file is loaded.
      • + *
      • and the file name does not exist in the schematic hierarchy or on the file system, + * the current associated screen file name is changed and saved to disk.
      • + *

      + * + * Note: the screen is not refresh. The caller is responsible to do that + */ + bool EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy ); + + wxPoint GetLastSheetPinPosition() const { return m_lastSheetPinPosition; } + +private: + /** + * Function CreateSheetPin + * creates a new SCH_SHEET_PIN object and add it to \a aSheet at the current cursor position. + * @param aSheet The sheet to add the new sheet pin to. + * @param aDC The device context to draw on. + * @return The new sheet pin object created or NULL if the task was aborted by the user. + */ + SCH_SHEET_PIN* CreateSheetPin( SCH_SHEET* aSheet, wxDC* aDC ); + + /** + * Function EditSheetPin + * displays the dialog for editing the parameters of \a aSheetPin. + * @param aSheetPin The sheet pin item to edit. + * @param aRedraw = true to refresh the screen + * @return The user response from the edit dialog. + */ + int EditSheetPin( SCH_SHEET_PIN* aSheetPin, bool aRedraw ); + + /** + * Function ImportSheetPin + * automatically creates a sheet pin from the hierarchical labels in the schematic + * referenced by \a aSheet. + * @param aSheet The sheet to import the new sheet pin to. + * @param aDC The device context to draw on. + * @return The new sheet pin object importd or NULL if the task was aborted by the user. + */ + SCH_SHEET_PIN* ImportSheetPin( SCH_SHEET* aSheet, wxDC* aDC ); + +public: + /** + * Function DeleteItem + * removes \a aItem from the current screen and saves it in the undo list. + * @param aItem The item to remove from the current screen. + */ + void DeleteItem( SCH_ITEM* aItem ); + + int GetLabelIncrement() const { return m_repeatLabelDelta; } + +private: + + /** + * Function Load_Component + * loads from a library and places a component. + * if libname != "", search in lib "libname" + * else search in all loaded libs + * + * @param aDC is the device context to draw upon. + * @param aFilters is a filter to pass the allowed lib names list, or library name + * to load the component from and/or some other filters + * if NULL, no filtering. + * @param aHistoryList list remembering recently used component names. + * @param aHistoryLastUnit remembering last unit in last component. + * @param aUseLibBrowser is the flag to determine if the library browser should be launched. + * @return a pointer the SCH_COMPONENT object selected or NULL if no component was selected. + * (TODO(hzeller): This really should be a class doing history, but didn't + * want to change too much while other refactoring is going on) + */ + SCH_COMPONENT* Load_Component( wxDC* aDC, + const SCHLIB_FILTER* aFilter, + wxArrayString& aHistoryList, + int& aHistoryLastUnit, + bool aUseLibBrowser ); + + /** + * Function EditComponent + * displays the edit component dialog to edit the parameters of \a aComponent. + * + * @param aComponent is a pointer to the SCH_COMPONENT object to be edited. + */ + void EditComponent( SCH_COMPONENT* aComponent ); + +public: + + /** + * Function OrientComponent + * rotates and mirrors a component. + */ + void OrientComponent( COMPONENT_ORIENTATION_T aOrientation = CMP_NORMAL ); + +private: + void OnSelectUnit( wxCommandEvent& aEvent ); + void ConvertPart( SCH_COMPONENT* DrawComponent, wxDC* DC ); + void SetInitCmp( SCH_COMPONENT* DrawComponent, wxDC* DC ); + + /** + * Function EditComponentFieldText + * displays the edit field dialog to edit the parameters of \a aField. + * + * @param aField is a pointer to the SCH_FIELD object to be edited. + */ + void EditComponentFieldText( SCH_FIELD* aField ); + + void RotateField( SCH_FIELD* aField, wxDC* aDC ); + + /** + * Function PastListOfItems + * pastes a list of items from the block stack. + */ + void PasteListOfItems( wxDC* DC ); + + /* Undo - redo */ +public: + + /** + * Function SaveCopyInUndoList. + * Create a copy of the current schematic item, and put it in the undo list. + * + * flag_type_command = + * UR_CHANGED + * UR_NEW + * UR_DELETED + * UR_WIRE_IMAGE + * UR_MOVED + * + * If it is a delete command, items are put on list with the .Flags member + * set to UR_DELETED. When it will be really deleted, the GetDrawItems() and the + * sub-hierarchy will be deleted. If it is only a copy, the GetDrawItems() and the + * sub-hierarchy must NOT be deleted. + * + * @note + * Edit wires and buses is a bit complex. + * because when a new wire is added, a lot of modifications in wire list is made + * (wire concatenation): modified items, deleted items and new items + * so flag_type_command is UR_WIRE_IMAGE: the struct ItemToCopy is a list of + * wires saved in Undo List (for Undo or Redo commands, saved wires will be + * exchanged with current wire list + * @param aItemToCopy = the schematic item modified by the command to undo + * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aTransformPoint = the reference point of the transformation, + * for commands like move + */ + void SaveCopyInUndoList( SCH_ITEM* aItemToCopy, + UNDO_REDO_T aTypeCommand, + const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); + + /** + * Function SaveCopyInUndoList (overloaded). + * Creates a new entry in undo list of commands. + * add a list of pickers to handle a list of items + * @param aItemsList = the list of items modified by the command to undo + * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aTransformPoint = the reference point of the transformation, + * for commands like move + */ + void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, + UNDO_REDO_T aTypeCommand, + const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); + +private: + + /** + * Function PutDataInPreviousState + * is used in undo or redo command to put data pointed by List in the previous state, i.e. + * the state stored in \a aList + * @param aList a PICKED_ITEMS_LIST pointer to the list of items to undo/redo + * @param aRedoCommand a bool: true for redo, false for undo + */ + void PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand ); + + /** + * Function GetSchematicFromRedoList + * Redo the last edition: + * - Save the current schematic in Undo list + * - Get an old version of the schematic from Redo list + * @return none + */ + void GetSchematicFromRedoList( wxCommandEvent& event ); + + /** + * Function GetSchematicFromUndoList + * performs an undo the last edition: + * - Save the current schematic in Redo list + * - Get an old version of the schematic from Undo list + */ + void GetSchematicFromUndoList( wxCommandEvent& event ); + + /** + * Function copyBlockItems + * copies the list of block item. + * @sa m_blockItems + * @param aItemsList List to copy the block select items into. + */ + void copyBlockItems( PICKED_ITEMS_LIST& aItemsList ); + + /** + * Function addJunctionMenuEntries + * adds the context menu items to \a aMenu for \a aJunction. + * @param aMenu The menu to add the items to. + * @param aJunction The SCH_JUNCTION object selected. + */ + void addJunctionMenuEntries( wxMenu* aMenu, SCH_JUNCTION* aJunction ); + +public: + void Key( wxDC* DC, int hotkey, EDA_ITEM* DrawStruct ); + + /** + * Function InitBlockPasteInfos + * initializes the parameters used by the block paste command. + */ + void InitBlockPasteInfos(); + + /** + * Function BlockCommand + * Returns the block command internat code (BLOCK_MOVE, BLOCK_COPY...) + * corresponding to the keys pressed (ALT, SHIFT, SHIFT ALT ..) when + * block command is started by dragging the mouse. + * @param aKey = the key modifiers (Alt, Shift ...) + * @return the block command id (BLOCK_MOVE, BLOCK_COPY...) + */ + virtual int BlockCommand( int aKey ); + + /** + * Function HandleBlockPlace + * Called after HandleBlockEnd, when a block command needs to be + * executed after the block is moved to its new place + * (bloc move, drag, copy .. ) + * Parameters must be initialized in GetScreen()->m_BlockLocate + */ + virtual void HandleBlockPlace( wxDC* DC ); + + /** + * Function HandleBlockEnd + * Handle the "end" of a block command, + * i.e. is called at the end of the definition of the area of a block. + * depending on the current block command, this command is executed + * or parameters are initialized to prepare a call to HandleBlockPlace + * in GetScreen()->m_BlockLocate + * + * @param aDC is a device context to draw on. + * @return false if no item selected, or command finished, + * true if some items found and HandleBlockPlace must be called later + */ + virtual bool HandleBlockEnd( wxDC* aDC ); + + /** + * Function RepeatDrawItem + * repeats the last item placement if the last item was a bus, bus entry, + * label, or component. + * + * Labels that end with a number will be incremented. + */ + void RepeatDrawItem( wxDC* DC ); + + /** + * Function SetRepeatItem + * clones aItem and owns that clone in this container. + */ + void SetRepeatItem( SCH_ITEM* aItem ); + + /** + * Function GetRepeatItem + * returns the item which is to be repeated with the insert key. Such object + * is owned by this container, and must be cloned. + */ + SCH_ITEM* GetRepeatItem() const { return m_item_to_repeat; } + + /** + * Function SetUndoItem + * clones \a aItem which can be used to restore the state of the item being edited + * when the user cancels the editing in progress. + * + * @param aItem The item to make a clone of for undoing the last change. Set to + * NULL to free the current undo item. + */ + void SetUndoItem( const SCH_ITEM* aItem ); + + SCH_ITEM* GetUndoItem() const { return m_undoItem; } + + /** + * Function SaveUndoItemInUndoList + * swaps the cloned item in member variable m_undoItem with \a aItem and saves it to + * the undo list then swap the data back. This swaps the internal structure of the + * item with the cloned item. It does not swap the actual item pointers themselves. + * + * @param aItem The item to swap with the current undo item. + */ + void SaveUndoItemInUndoList( SCH_ITEM* aItem ); + + /** + * Function CreateArchiveLibraryCacheFile + * creates a library file with the name of the root document plus the '-cache' suffix, + * That file will contain all components used in the current schematic. + * + * @param aUseCurrentSheetFilename = false to use the root shhet filename + * (default) or true to use the currently opened sheet. + * @return true if the file was written successfully. + */ + bool CreateArchiveLibraryCacheFile( bool aUseCurrentSheetFilename = false ); + + /** + * Function CreateArchiveLibrary + * creates a library \a aFileName that contains all components used in the current schematic. + * + * @param aFileName The full path and file name of the archive library. + * @return True if \a aFileName was written successfully. + */ + bool CreateArchiveLibrary( const wxString& aFileName ); + + /** + * Function RescueProject + * performs rescue operations to recover old projects from before certain + * changes were made. + * + * - Exports cached symbols that conflict with new symbols to a separate + * library + * - Renames symbols named before libraries were case sensitive + * + * @param aRunningOnDemand - indicates whether the tool has been called up by the user + * (as opposed to being run automatically). If true, an information dialog is + * displayed if there are no components to rescue. If false, the tool is silent + * if there are no components to rescue, and a "Never Show Again" button is + * displayed. + */ + bool RescueProject( bool aRunningOnDemand ); + + /** + * Function PrintPage + * plots or prints the current sheet to the clipboard. + * @param aDC = wxDC given by the calling print function + * @param aPrintMask = not used here + * @param aPrintMirrorMode = not used here (Set when printing in mirror mode) + * @param aData = a pointer on an auxiliary data (not always used, NULL if not used) + */ + virtual void PrintPage( wxDC* aDC, LSET aPrintMask, + bool aPrintMirrorMode, void* aData = NULL ); + + void SetSimulatorCommand( const wxString& aCommand ) { m_simulatorCommand = aCommand; } + + wxString GetSimulatorCommand() const { return m_simulatorCommand; } + + void SetNetListerCommand( const wxString& aCommand ) { m_netListerCommand = aCommand; } + + wxString GetNetListerCommand() const { return m_netListerCommand; } + + DECLARE_EVENT_TABLE() +}; + + +#endif // WX_EESCHEMA_STRUCT_H diff --git a/eeschema/selpart.cpp b/eeschema/selpart.cpp new file mode 100644 index 00000000..b0b36297 --- /dev/null +++ b/eeschema/selpart.cpp @@ -0,0 +1,163 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 + */ + +/** + * @file selpart.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +// Used in DisplayListComponentsInLib: this is a callback function for EDA_LIST_DIALOG +// to display keywords and description of a component +static void DisplayCmpDocAndKeywords( wxString& aName, void* aData ) +{ + PART_LIBS* libs = (PART_LIBS*) aData; + + wxASSERT( libs ); + + LIB_ALIAS* part = libs->FindLibraryEntry( aName ); + + if( !part ) + return; + + aName = wxT( "Description: " ) + part->GetDescription(); + aName += wxT( "\nKey Words: " ) + part->GetKeyWords(); +} + + +PART_LIB* SCH_BASE_FRAME::SelectLibraryFromList() +{ + PROJECT& prj = Prj(); + + if( PART_LIBS* libs = prj.SchLibs() ) + { + if( !libs->GetLibraryCount() ) + { + DisplayError( this, _( "No component libraries are loaded." ) ); + return NULL; + } + + wxArrayString headers; + + headers.Add( wxT( "Library" ) ); + + wxArrayString libNamesList = libs->GetLibraryNames(); + + std::vector itemsToDisplay; + + // Conversion from wxArrayString to vector of ArrayString + for( unsigned i = 0; i < libNamesList.GetCount(); i++ ) + { + wxArrayString item; + + item.Add( libNamesList[i] ); + + itemsToDisplay.push_back( item ); + } + + wxString old_lib_name = prj.GetRString( PROJECT::SCH_LIB_SELECT ); + + EDA_LIST_DIALOG dlg( this, _( "Select Library" ), headers, itemsToDisplay, old_lib_name ); + + if( dlg.ShowModal() != wxID_OK ) + return NULL; + + wxString libname = dlg.GetTextSelection(); + + if( !libname ) + return NULL; + + PART_LIB* lib = libs->FindLibrary( libname ); + + if( lib ) + prj.SetRString( PROJECT::SCH_LIB_SELECT, libname ); + + return lib; + } + + return NULL; +} + + + +bool SCH_BASE_FRAME::DisplayListComponentsInLib( PART_LIB* aLibrary, + wxString& aBuffer, wxString& aPreviousChoice ) +{ + wxArrayString nameList; + + if( aLibrary == NULL ) + aLibrary = SelectLibraryFromList(); + + if( aLibrary == NULL ) + return false; + + aLibrary->GetEntryNames( nameList ); + + wxArrayString headers; + headers.Add( wxT("Component") ); + headers.Add( wxT("Library") ); + std::vector itemsToDisplay; + + // Conversion from wxArrayString to vector of ArrayString + for( unsigned i = 0; i < nameList.GetCount(); i++ ) + { + wxArrayString item; + item.Add( nameList[i] ); + item.Add( aLibrary->GetLogicalName() ); + itemsToDisplay.push_back( item ); + } + + EDA_LIST_DIALOG dlg( this, _( "Select Component" ), headers, itemsToDisplay, + aPreviousChoice, DisplayCmpDocAndKeywords, Prj().SchLibs() ); + + if( dlg.ShowModal() != wxID_OK ) + return false; + + aBuffer = dlg.GetTextSelection(); + + return true; +} + + +bool SCH_BASE_FRAME::SelectPartNameToLoad( PART_LIB* aLibrary, wxString& aBufName ) +{ + int ii; + static wxString previousCmpName; + + ii = DisplayListComponentsInLib( aLibrary, aBufName, previousCmpName ); + + if( ii <= 0 || aBufName.IsEmpty() ) + return false; + + previousCmpName = aBufName; + return true; +} diff --git a/eeschema/sheet.cpp b/eeschema/sheet.cpp new file mode 100644 index 00000000..95005c67 --- /dev/null +++ b/eeschema/sheet.cpp @@ -0,0 +1,452 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file sheet.cpp + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy ) +{ + if( aSheet == NULL || aHierarchy == NULL ) + return false; + + SCH_SHEET_LIST hierarchy; // This is the schematic sheet hierarchy. + + // Get the new texts + DIALOG_SCH_SHEET_PROPS dlg( this ); + + wxString units = GetUnitsLabel( g_UserUnit ); + dlg.SetFileName( aSheet->GetFileName() ); + dlg.SetFileNameTextSize( StringFromValue( g_UserUnit, aSheet->GetFileNameSize() ) ); + dlg.SetFileNameTextSizeUnits( units ); + dlg.SetSheetName( aSheet->GetName() ); + dlg.SetSheetNameTextSize( StringFromValue( g_UserUnit, aSheet->GetSheetNameSize() ) ); + dlg.SetSheetNameTextSizeUnits( units ); + dlg.SetSheetTimeStamp( wxString::Format( wxT("%8.8lX"), + (unsigned long) aSheet->GetTimeStamp() ) ); + + /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier + * versions for the flex grid sizer in wxGTK that prevents the last + * column from being sized correctly. It doesn't cause any problems + * on win32 so it doesn't need to wrapped in ugly #ifdef __WXGTK__ + * #endif. + * Still presen in wxWidgets 3.0.2 + */ + dlg.Layout(); + dlg.Fit(); + dlg.SetMinSize( dlg.GetSize() ); + dlg.GetSizer()->Fit( &dlg ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + wxFileName fileName = dlg.GetFileName(); + fileName.SetExt( SchematicFileExtension ); + + if( !fileName.IsOk() ) + { + DisplayError( this, _( "File name is not valid!" ) ); + return false; + } + + // Duplicate sheet names are not valid. + const SCH_SHEET* sheet = hierarchy.FindSheetByName( dlg.GetSheetName() ); + + if( sheet && (sheet != aSheet) ) + { + DisplayError( this, wxString::Format( _( "A sheet named \"%s\" already exists." ), + GetChars( dlg.GetSheetName() ) ) ); + return false; + } + + wxString msg; + bool loadFromFile = false; + SCH_SCREEN* useScreen = NULL; + + wxString newFilename = fileName.GetFullPath(); + + // Search for a schematic file having the same filename + // already in use in the hierarchy or on disk, in order to reuse it. + if( !g_RootSheet->SearchHierarchy( newFilename, &useScreen ) ) + { + // if user entered a relative path, allow that to stay, but do the + // file existence test with an absolute (full) path. This transformation + // is local to this scope, but is the same one used at load time later. + wxString absolute = Prj().AbsolutePath( newFilename ); + + loadFromFile = wxFileExists( absolute ); + } + + // Inside Eeschema, filenames are stored using unix notation + newFilename.Replace( wxT( "\\" ), wxT( "/" ) ); + + if( aSheet->GetScreen() == NULL ) // New sheet. + { + if( useScreen || loadFromFile ) // Load from existing file. + { + if( useScreen != NULL ) + { + msg.Printf( _( "A file named '%s' already exists in the current schematic " + "hierarchy." ), GetChars( newFilename ) ); + } + else + { + msg.Printf( _( "A file named '%s' already exists." ), GetChars( newFilename ) ); + } + + msg += _( "\n\nDo you want to create a sheet with the contents of this file?" ); + + if( !IsOK( this, msg ) ) + { + return false; + } + } + else // New file. + { + aSheet->SetScreen( new SCH_SCREEN( &Kiway() ) ); + aSheet->GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax ); + aSheet->GetScreen()->SetFileName( newFilename ); + } + } + else // Existing sheet. + { + bool isUndoable = true; + bool renameFile = false; + + // We are always using here a case insensitive comparison + // to avoid issues under Windows, although under Unix + // filenames are case sensitive. + // But many users create schematic under both Unix and Windows + if( newFilename.CmpNoCase( aSheet->GetFileName() ) != 0 ) + { + // Sheet file name changes cannot be undone. + isUndoable = false; + msg = _( "Changing the sheet file name cannot be undone. " ); + + if( useScreen || loadFromFile ) // Load from existing file. + { + wxString tmp; + + if( useScreen != NULL ) + { + tmp.Printf( _( "A file named <%s> already exists in the current schematic " + "hierarchy." ), GetChars( newFilename ) ); + } + else + { + tmp.Printf( _( "A file named <%s> already exists." ), + GetChars( newFilename ) ); + } + + msg += tmp; + msg += _( "\n\nDo you want to replace the sheet with the contents of this file?" ); + + if( !IsOK( this, msg ) ) + return false; + + if( loadFromFile ) + aSheet->SetScreen( NULL ); + } + else // Save to new file name. + { + if( aSheet->GetScreenCount() > 1 ) + { + msg += _( "This sheet uses shared data in a complex hierarchy.\n\n" ); + msg += _( "Do you wish to convert it to a simple hierarchical sheet?" ); + + if( !IsOK( NULL, msg ) ) + return false; + } + + renameFile = true; + } + } + + m_canvas->SetIgnoreMouseEvents( true ); + + if( isUndoable ) + SaveCopyInUndoList( aSheet, UR_CHANGED ); + + if( renameFile ) + { + aSheet->GetScreen()->SetFileName( newFilename ); + SaveEEFile( aSheet->GetScreen() ); + + // If the the associated screen is shared by more than one sheet, remove the + // screen and reload the file to a new screen. Failure to do this will trash + // the screen reference counting in complex hierarchies. + if( aSheet->GetScreenCount() > 1 ) + { + aSheet->SetScreen( NULL ); + loadFromFile = true; + } + } + } + + aSheet->SetFileName( newFilename ); + + if( useScreen ) + aSheet->SetScreen( useScreen ); + else if( loadFromFile ) + aSheet->Load( this ); + + aSheet->SetFileNameSize( ValueFromString( g_UserUnit, dlg.GetFileNameTextSize() ) ); + aSheet->SetName( dlg.GetSheetName() ); + aSheet->SetSheetNameSize( ValueFromString( g_UserUnit, dlg.GetSheetNameTextSize() ) ); + + if( aSheet->GetName().IsEmpty() ) + aSheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ), + (long unsigned) aSheet->GetTimeStamp() ) ); + + // Make sure the sheet changes do not cause any recursion. + SCH_SHEET_LIST sheetHierarchy( aSheet ); + + // Make sure files have fully qualified path and file name. + wxFileName destFn = aHierarchy->Last()->GetFileName(); + + if( destFn.IsRelative() ) + destFn.MakeAbsolute( Prj().GetProjectPath() ); + + if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) ) + { + msg.Printf( _( "The sheet changes cannot be made because the destination sheet already " + "has the sheet <%s> or one of it's subsheets as a parent somewhere in " + "the schematic hierarchy." ), + GetChars( newFilename ) ); + DisplayError( this, msg ); + return false; + } + + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + OnModify(); + + return true; +} + + +/* Move selected sheet with the cursor. + * Callback function used by m_mouseCaptureCallback. + * Note also now this function is aclled only when resizing the sheet + * But the (very small code) relative to sheet move is still present here + */ +static void resizeSheetWithMouseCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + BASE_SCREEN* screen = aPanel->GetScreen(); + SCH_SHEET* sheet = (SCH_SHEET*) screen->GetCurItem(); + + if( aErase ) + sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); + + wxPoint pos = sheet->GetPosition(); + + int width = aPanel->GetParent()->GetCrossHairPosition().x - sheet->GetPosition().x; + int height = aPanel->GetParent()->GetCrossHairPosition().y - sheet->GetPosition().y; + + // If the sheet doesn't have any pins, clamp the minimum size to the default values. + width = ( width < MIN_SHEET_WIDTH ) ? MIN_SHEET_WIDTH : width; + height = ( height < MIN_SHEET_HEIGHT ) ? MIN_SHEET_HEIGHT : height; + + if( sheet->HasPins() ) + { + int gridSizeX = KiROUND( screen->GetGridSize().x ); + int gridSizeY = KiROUND( screen->GetGridSize().y ); + + // If the sheet has pins, use the pin positions to clamp the minimum height. + height = ( height < sheet->GetMinHeight() + gridSizeY ) ? + sheet->GetMinHeight() + gridSizeY : height; + width = ( width < sheet->GetMinWidth() + gridSizeX ) ? + sheet->GetMinWidth() + gridSizeX : width; + } + + wxPoint grid = aPanel->GetParent()->GetNearestGridPosition( + wxPoint( pos.x + width, pos.y + height ) ); + sheet->Resize( wxSize( grid.x - pos.x, grid.y - pos.y ) ); + + sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); +} + + +// Complete sheet move. +static void ExitSheet( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) +{ + SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); + SCH_ITEM* item = screen->GetCurItem(); + + SCH_EDIT_FRAME* parent = (SCH_EDIT_FRAME*) aPanel->GetParent(); + + if( (item == NULL) || (item->Type() != SCH_SHEET_T) || (parent == NULL) ) + return; + + parent->SetRepeatItem( NULL ); + + item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); + + if( item->IsNew() ) + { + delete item; + } + else if( item->IsMoving() || item->IsResized() ) + { + screen->Remove( item ); + delete item; + + item = parent->GetUndoItem(); + + wxCHECK_RET( item != NULL, wxT( "Cannot restore undefined last sheet item." ) ); + + screen->Append( item ); + // the owner of item is no more parent, this is the draw list of screen: + parent->SetUndoItem( NULL ); + + item->Draw( aPanel, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); + item->ClearFlags(); + } + else + { + item->ClearFlags(); + } + + screen->SetCurItem( NULL ); +} + + +// Create hierarchy sheet. +SCH_SHEET* SCH_EDIT_FRAME::CreateSheet( wxDC* aDC ) +{ + SetRepeatItem( NULL ); + + SCH_SHEET* sheet = new SCH_SHEET( GetCrossHairPosition() ); + + sheet->SetFlags( IS_NEW | IS_RESIZED ); + sheet->SetTimeStamp( GetNewTimeStamp() ); + sheet->SetParent( GetScreen() ); + sheet->SetScreen( NULL ); + + // need to check if this is being added to the GetDrawItems(). + // also need to update the hierarchy, if we are adding + // a sheet to a screen that already has multiple instances (!) + GetScreen()->SetCurItem( sheet ); + m_canvas->SetMouseCapture( resizeSheetWithMouseCursor, ExitSheet ); + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); + m_canvas->CrossHairOff( aDC ); + + SetCrossHairPosition( sheet->GetResizePosition() ); + + m_canvas->MoveCursorToCrossHair(); + m_canvas->CrossHairOn( aDC ); + + return sheet; +} + + +void SCH_EDIT_FRAME::ReSizeSheet( SCH_SHEET* aSheet, wxDC* aDC ) +{ + if( aSheet == NULL || aSheet->IsNew() ) + return; + + wxCHECK_RET( aSheet->Type() == SCH_SHEET_T, + wxString::Format( wxT( "Cannot perform sheet resize on %s object." ), + GetChars( aSheet->GetClass() ) ) ); + + m_canvas->CrossHairOff( aDC ); + SetCrossHairPosition( aSheet->GetResizePosition() ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->CrossHairOn( aDC ); + + SetUndoItem( aSheet ); + aSheet->SetFlags( IS_RESIZED ); + + m_canvas->SetMouseCapture( resizeSheetWithMouseCursor, ExitSheet ); + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true ); + + if( aSheet->IsNew() ) // not already in edit, save a copy for undo/redo + SetUndoItem( aSheet ); +} + + +void SCH_EDIT_FRAME::RotateHierarchicalSheet( SCH_SHEET* aSheet, bool aRotCCW ) +{ + if( aSheet == NULL ) + return; + + // Save old sheet in undo list if not already in edit, or moving. + if( aSheet->GetFlags() == 0 ) + SaveCopyInUndoList( aSheet, UR_CHANGED ); + + // Rotate the sheet on itself. Sheets do not have a anchor point. + // Rotation is made around it center + wxPoint rotPoint = aSheet->GetBoundingBox().Centre(); + + // rotate CCW, or CW. to rotate CW, rotate 3 times + aSheet->Rotate( rotPoint ); + + if( !aRotCCW ) + { + aSheet->Rotate( rotPoint ); + aSheet->Rotate( rotPoint ); + } + + GetCanvas()->Refresh(); + OnModify(); +} + + +void SCH_EDIT_FRAME::MirrorSheet( SCH_SHEET* aSheet, bool aFromXaxis ) +{ + if( aSheet == NULL ) + return; + + // Save old sheet in undo list if not already in edit, or moving. + if( aSheet->GetFlags() == 0 ) + SaveCopyInUndoList( aSheet, UR_CHANGED ); + + // Mirror the sheet on itself. Sheets do not have a anchor point. + // Mirroring is made around it center + wxPoint mirrorPoint = aSheet->GetBoundingBox().Centre(); + + if( aFromXaxis ) // mirror relative to Horizontal axis + aSheet->MirrorX( mirrorPoint.y ); + else // Mirror relative to vertical axis + aSheet->MirrorY( mirrorPoint.x ); + + GetCanvas()->Refresh(); + OnModify(); +} diff --git a/eeschema/sheetlab.cpp b/eeschema/sheetlab.cpp new file mode 100644 index 00000000..aeca4835 --- /dev/null +++ b/eeschema/sheetlab.cpp @@ -0,0 +1,179 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2015 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 + */ + +/** + * @file sheetlab.cpp + * @brief Create and edit the SCH_SHEET_PIN items. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +int SCH_EDIT_FRAME::m_lastSheetPinType = NET_INPUT; +wxSize SCH_EDIT_FRAME::m_lastSheetPinTextSize( -1, -1 ); +wxPoint SCH_EDIT_FRAME::m_lastSheetPinPosition; + +const wxSize &SCH_EDIT_FRAME::GetLastSheetPinTextSize() +{ + // Delayed initialization (need the preferences to be loaded) + if( m_lastSheetPinTextSize.x == -1 ) + { + m_lastSheetPinTextSize.x = GetDefaultTextSize(); + m_lastSheetPinTextSize.y = GetDefaultTextSize(); + } + return m_lastSheetPinTextSize; +} + +int SCH_EDIT_FRAME::EditSheetPin( SCH_SHEET_PIN* aSheetPin, bool aRedraw ) +{ + if( aSheetPin == NULL ) + return wxID_CANCEL; + + DIALOG_SCH_EDIT_SHEET_PIN dlg( this ); + + dlg.SetLabelName( aSheetPin->GetText() ); + dlg.SetTextHeight( StringFromValue( g_UserUnit, aSheetPin->GetSize().y ) ); + dlg.SetTextHeightUnits( GetUnitsLabel( g_UserUnit ) ); + dlg.SetTextWidth( StringFromValue( g_UserUnit, aSheetPin->GetSize().x ) ); + dlg.SetTextWidthUnits( GetUnitsLabel( g_UserUnit ) ); + dlg.SetConnectionType( aSheetPin->GetShape() ); + + /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier versions for + * the flex grid sizer in wxGTK that prevents the last column from being sized + * correctly. It doesn't cause any problems on win32 so it doesn't need to wrapped + * in ugly #ifdef __WXGTK__ #endif. + */ + dlg.Layout(); + dlg.Fit(); + dlg.SetMinSize( dlg.GetSize() ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return wxID_CANCEL; + + if( !aSheetPin->IsNew() ) + { + SaveCopyInUndoList( (SCH_ITEM*) aSheetPin->GetParent(), UR_CHANGED ); + GetScreen()->SetCurItem( NULL ); + } + + aSheetPin->SetText( dlg.GetLabelName() ); + aSheetPin->SetSize( wxSize( ValueFromString( g_UserUnit, dlg.GetTextWidth() ), + ValueFromString( g_UserUnit, dlg.GetTextHeight() ) ) ); + aSheetPin->SetShape( dlg.GetConnectionType() ); + + OnModify(); + + if( aRedraw ) + m_canvas->Refresh(); + + return wxID_OK; +} + + +SCH_SHEET_PIN* SCH_EDIT_FRAME::CreateSheetPin( SCH_SHEET* aSheet, wxDC* aDC ) +{ + wxString line; + SCH_SHEET_PIN* sheetPin; + + sheetPin = new SCH_SHEET_PIN( aSheet, wxPoint( 0, 0 ), line ); + sheetPin->SetFlags( IS_NEW ); + sheetPin->SetSize( GetLastSheetPinTextSize() ); + sheetPin->SetShape( m_lastSheetPinType ); + + int response = EditSheetPin( sheetPin, false ); + + if( sheetPin->GetText().IsEmpty() || (response == wxID_CANCEL) ) + { + delete sheetPin; + return NULL; + } + + m_lastSheetPinType = sheetPin->GetShape(); + m_lastSheetPinTextSize = sheetPin->GetSize(); + + sheetPin->SetPosition( GetCrossHairPosition() ); + sheetPin->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( (SCH_ITEM*) sheetPin, aDC ); + + OnModify(); + return sheetPin; +} + + +SCH_SHEET_PIN* SCH_EDIT_FRAME::ImportSheetPin( SCH_SHEET* aSheet, wxDC* aDC ) +{ + EDA_ITEM* item; + SCH_SHEET_PIN* sheetPin; + SCH_HIERLABEL* label = NULL; + + if( !aSheet->GetScreen() ) + return NULL; + + item = aSheet->GetScreen()->GetDrawItems(); + + for( ; item != NULL; item = item->Next() ) + { + if( item->Type() != SCH_HIERARCHICAL_LABEL_T ) + continue; + + label = (SCH_HIERLABEL*) item; + + /* A global label has been found: check if there a corresponding sheet label. */ + if( !aSheet->HasPin( label->GetText() ) ) + break; + + label = NULL; + } + + if( label == NULL ) + { + DisplayInfoMessage( this, _( "No new hierarchical labels found." ) ); + return NULL; + } + + sheetPin = new SCH_SHEET_PIN( aSheet, wxPoint( 0, 0 ), label->GetText() ); + sheetPin->SetFlags( IS_NEW ); + sheetPin->SetSize( GetLastSheetPinTextSize() ); + m_lastSheetPinType = label->GetShape(); + sheetPin->SetShape( label->GetShape() ); + sheetPin->SetPosition( GetCrossHairPosition() ); + + sheetPin->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode ); + PrepareMoveItem( (SCH_ITEM*) sheetPin, aDC ); + + return sheetPin; +} diff --git a/eeschema/symbdraw.cpp b/eeschema/symbdraw.cpp new file mode 100644 index 00000000..10b81b85 --- /dev/null +++ b/eeschema/symbdraw.cpp @@ -0,0 +1,370 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2009-2017 Wayne Stambaugh + * Copyright (C) 2004-2017 KiCad Developers, see change_log.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 + */ + +/** + * @file symbdraw.cpp + * @brief Create, move .. graphic shapes used to build and draw a component (lines, arcs ..) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static void SymbolDisplayDraw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ); +static void RedrawWhileMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ); + + +void LIB_EDIT_FRAME::EditGraphicSymbol( wxDC* DC, LIB_ITEM* DrawItem ) +{ + if( DrawItem == NULL ) + return; + + LIB_PART* component = DrawItem->GetParent(); + + DIALOG_LIB_EDIT_DRAW_ITEM dialog( this, DrawItem->GetTypeName() ); + + dialog.SetWidthUnits( ReturnUnitSymbol( g_UserUnit ) ); + + wxString val = StringFromValue( g_UserUnit, DrawItem->GetWidth() ); + dialog.SetWidth( val ); + dialog.SetApplyToAllUnits( DrawItem->GetUnit() == 0 ); + dialog.EnableApplyToAllUnits( component && component->GetUnitCount() > 1 ); + dialog.SetApplyToAllConversions( DrawItem->GetConvert() == 0 ); + dialog.EnableApplyToAllConversions( component && component->HasConversion() ); + dialog.SetFillStyle( DrawItem->GetFillMode() ); + dialog.EnableFillStyle( DrawItem->IsFillable() ); + + if( dialog.ShowModal() == wxID_CANCEL ) + return; + + // Init default values (used to create a new draw item) + val = dialog.GetWidth(); + m_drawLineWidth = ValueFromString( g_UserUnit, val ); + m_drawSpecificConvert = !dialog.GetApplyToAllConversions(); + m_drawSpecificUnit = !dialog.GetApplyToAllUnits(); + +#if 0 + /* TODO: see if m_drawFillStyle must retain the last fill option or not. + * if the last is Filled, having next new graphic items created + * with filled body is often bad. + * currently m_drawFillStyle is left with the default value (not filled) + */ + if( DrawItem->IsFillable() ) + m_drawFillStyle = (FILL_T) dialog.GetFillStyle(); +#endif + + // Save copy for undo if not in edit (edit command already handle the save copy) + if( !DrawItem->InEditMode() ) + SaveCopyInUndoList( DrawItem->GetParent() ); + + if( m_drawSpecificUnit ) + DrawItem->SetUnit( GetUnit() ); + else + DrawItem->SetUnit( 0 ); + + if( m_drawSpecificConvert ) + DrawItem->SetConvert( GetConvert() ); + else + DrawItem->SetConvert( 0 ); + + if( DrawItem->IsFillable() ) + DrawItem->SetFillMode( (FILL_T) dialog.GetFillStyle() ); + + DrawItem->SetWidth( m_drawLineWidth ); + + if( component ) + component->GetDrawItemList().sort(); + + OnModify( ); + + MSG_PANEL_ITEMS items; + DrawItem->GetMsgPanelInfo( items ); + SetMsgPanel( items ); + m_canvas->Refresh(); +} + + +static void AbortSymbolTraceOn( EDA_DRAW_PANEL* Panel, wxDC* DC ) +{ + LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) Panel->GetParent(); + LIB_ITEM* item = parent->GetDrawItem(); + + if( item == NULL ) + return; + + bool newItem = item->IsNew(); + item->EndEdit( parent->GetCrossHairPosition( true ), true ); + + if( newItem ) + { + delete item; + } + else + parent->RestoreComponent(); + + parent->SetDrawItem( NULL ); + Panel->Refresh(); +} + + +LIB_ITEM* LIB_EDIT_FRAME::CreateGraphicItem( LIB_PART* LibEntry, wxDC* DC ) +{ + m_canvas->SetMouseCapture( SymbolDisplayDraw, AbortSymbolTraceOn ); + wxPoint drawPos = GetCrossHairPosition( true ); + + // no temp copy -> the current version of component will be used for Undo + // This is normal when adding new items to the current component + ClearTempCopyComponent(); + + switch( GetToolId() ) + { + case ID_LIBEDIT_BODY_ARC_BUTT: + m_drawItem = new LIB_ARC( LibEntry ); + break; + + case ID_LIBEDIT_BODY_CIRCLE_BUTT: + m_drawItem = new LIB_CIRCLE( LibEntry ); + break; + + case ID_LIBEDIT_BODY_RECT_BUTT: + m_drawItem = new LIB_RECTANGLE( LibEntry ); + break; + + case ID_LIBEDIT_BODY_LINE_BUTT: + m_drawItem = new LIB_POLYLINE( LibEntry ); + break; + + case ID_LIBEDIT_BODY_TEXT_BUTT: + { + LIB_TEXT* Text = new LIB_TEXT( LibEntry ); + Text->SetSize( wxSize( m_textSize, m_textSize ) ); + Text->SetOrientation( m_textOrientation ); + + // Enter the graphic text info + m_canvas->SetIgnoreMouseEvents( true ); + EditSymbolText( NULL, Text ); + m_canvas->SetIgnoreMouseEvents( false ); + m_canvas->MoveCursorToCrossHair(); + + if( Text->GetText().IsEmpty() ) + { + delete Text; + m_drawItem = NULL; + } + else + { + m_drawItem = Text; + } + } + break; + + default: + DisplayError( this, wxT( "LIB_EDIT_FRAME::CreateGraphicItem() error" ) ); + return NULL; + } + + if( m_drawItem ) + { + m_drawItem->BeginEdit( IS_NEW, drawPos ); + + // Don't set line parameters for text objects. + if( m_drawItem->Type() != LIB_TEXT_T ) + { + m_drawItem->SetWidth( m_drawLineWidth ); + m_drawItem->SetFillMode( m_drawFillStyle ); + } + + if( m_drawSpecificUnit ) + m_drawItem->SetUnit( m_unit ); + + if( m_drawSpecificConvert ) + m_drawItem->SetConvert( m_convert ); + + // Draw initial symbol: + m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); + } + else + { + m_canvas->EndMouseCapture(); + return NULL; + } + + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + + return m_drawItem; +} + + +void LIB_EDIT_FRAME::GraphicItemBeginDraw( wxDC* DC ) +{ + if( m_drawItem == NULL ) + return; + + wxPoint pos = GetCrossHairPosition( true ); + + if( m_drawItem->ContinueEdit( pos ) ) + { + m_drawItem->Draw( m_canvas, DC, pos, UNSPECIFIED_COLOR, g_XorMode, NULL, DefaultTransform ); + return; + } + + EndDrawGraphicItem( DC ); +} + + +/* + * Redraw the graphic shape while moving + */ +static void RedrawWhileMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + LIB_ITEM* item; + + item = ( (LIB_EDIT_FRAME*) aPanel->GetParent() )->GetDrawItem(); + + if( item == NULL ) + return; + + item->SetEraseLastDrawItem( aErase ); + + // if item is the reference field, we must add the current unit id + if( item->Type() == LIB_FIELD_T ) + { + int unit = ((LIB_EDIT_FRAME*)aPanel->GetParent())->GetUnit(); + wxString text = ((LIB_FIELD*)item)->GetFullText( unit ); + + item->Draw( aPanel, aDC, aPanel->GetParent()->GetCrossHairPosition( true ), + UNSPECIFIED_COLOR, g_XorMode, &text, + DefaultTransform ); + } + else + item->Draw( aPanel, aDC, aPanel->GetParent()->GetCrossHairPosition( true ), + UNSPECIFIED_COLOR, g_XorMode, NULL, + DefaultTransform ); +} + + +void LIB_EDIT_FRAME::StartMoveDrawSymbol( wxDC* DC ) +{ + if( m_drawItem == NULL ) + return; + + SetCursor( wxCURSOR_HAND ); + + TempCopyComponent(); + + // For fields only, move the anchor point of the field + // to the cursor position to allow user to see the text justification + if( m_drawItem->Type() == LIB_FIELD_T ) + m_drawItem->BeginEdit( IS_MOVED, m_drawItem->GetPosition() ); + else + m_drawItem->BeginEdit( IS_MOVED, GetCrossHairPosition( true ) ); + + m_canvas->SetMouseCapture( RedrawWhileMovingCursor, AbortSymbolTraceOn ); + m_canvas->CallMouseCapture( DC, wxDefaultPosition, true ); +} + + +void LIB_EDIT_FRAME::StartModifyDrawSymbol( wxDC* DC ) +{ + if( m_drawItem == NULL ) + return; + + TempCopyComponent(); + m_drawItem->BeginEdit( IS_RESIZED, GetCrossHairPosition( true ) ); + m_canvas->SetMouseCapture( SymbolDisplayDraw, AbortSymbolTraceOn ); + m_canvas->CallMouseCapture( DC, wxDefaultPosition, true ); +} + + +//! @brief Manage mouse events when creating new graphic object or modifying an graphic object. +static void SymbolDisplayDraw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, + bool aErase ) +{ + LIB_ITEM* item = ( (LIB_EDIT_FRAME*) aPanel->GetParent() )->GetDrawItem(); + + if( item == NULL ) + return; + + item->SetEraseLastDrawItem( aErase ); + item->Draw( aPanel, aDC, aPanel->GetParent()->GetCrossHairPosition( true ), UNSPECIFIED_COLOR, + g_XorMode, NULL, DefaultTransform ); +} + + +void LIB_EDIT_FRAME::EndDrawGraphicItem( wxDC* DC ) +{ + if( LIB_PART* part = GetCurPart() ) + { + if( !m_drawItem ) + return; + + if( GetToolId() != ID_NO_TOOL_SELECTED ) + SetCursor( wxCURSOR_PENCIL ); + else + SetCursor( (wxStockCursor) m_canvas->GetDefaultCursor() ); + + if( GetTempCopyComponent() ) // used when editing an existing item + SaveCopyInUndoList( GetTempCopyComponent() ); + else + { + // When creating a new item, there is still no change for the + // current component. So save it. + SaveCopyInUndoList( part ); + } + + if( m_drawItem->IsNew() ) + part->AddDrawItem( m_drawItem ); + + m_drawItem->EndEdit( GetCrossHairPosition( true ) ); + + m_drawItem = NULL; + + OnModify(); + + m_canvas->SetMouseCapture( NULL, NULL ); + m_canvas->Refresh(); + } +} diff --git a/eeschema/symbedit.cpp b/eeschema/symbedit.cpp new file mode 100644 index 00000000..10536b33 --- /dev/null +++ b/eeschema/symbedit.cpp @@ -0,0 +1,269 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file symbedit.cpp + * @brief Functions to load from and save to file component libraries and symbols. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +void LIB_EDIT_FRAME::LoadOneSymbol() +{ + LIB_PART* part = GetCurPart(); + + // Exit if no library entry is selected or a command is in progress. + if( !part || ( m_drawItem && m_drawItem->GetFlags() ) ) + return; + + PROJECT& prj = Prj(); + SEARCH_STACK* search = prj.SchSearchS(); + + m_canvas->SetIgnoreMouseEvents( true ); + + wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); + if( !default_path ) + default_path = search->LastVisitedPath(); + + wxFileDialog dlg( this, _( "Import Symbol Drawings" ), default_path, + wxEmptyString, SchematicSymbolFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + SetCrossHairPosition( wxPoint( 0, 0 ) ); + m_canvas->MoveCursorToCrossHair(); + m_canvas->SetIgnoreMouseEvents( false ); + + wxString filename = dlg.GetPath(); + + prj.SetRString( PROJECT::SCH_LIB_PATH, filename ); + + std::auto_ptr lib( new PART_LIB( LIBRARY_TYPE_SYMBOL, filename ) ); + + wxString err; + + if( !lib->Load( err ) ) + { + wxString msg = wxString::Format( _( + "Error '%s' occurred loading part file '%s'." ), + GetChars( err ), + GetChars( filename ) + ); + DisplayError( this, msg ); + return; + } + + if( lib->IsEmpty() ) + { + wxString msg = wxString::Format( _( + "No parts found in part file '%s'." ), + GetChars( filename ) + ); + DisplayError( this, msg ); + return; + } + + if( lib->GetCount() > 1 ) + { + wxString msg = wxString::Format( _( + "More than one part in part file '%s'." ), + GetChars( filename ) + ); + wxMessageBox( msg, _( "Warning" ), wxOK | wxICON_EXCLAMATION, this ); + } + + LIB_PART* first = lib->GetFirstEntry()->GetPart(); + LIB_ITEMS& drawList = first->GetDrawItemList(); + + BOOST_FOREACH( LIB_ITEM& item, drawList ) + { + if( item.Type() == LIB_FIELD_T ) + continue; + + if( item.GetUnit() ) + item.SetUnit( m_unit ); + + if( item.GetConvert() ) + item.SetConvert( m_convert ); + + item.SetFlags( IS_NEW | SELECTED ); + + LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); + + newItem->SetParent( part ); + part->AddDrawItem( newItem ); + } + + part->RemoveDuplicateDrawItems(); + part->ClearSelectedItems(); + + OnModify(); + m_canvas->Refresh(); +} + + +void LIB_EDIT_FRAME::SaveOneSymbol() +{ + wxString msg; + PROJECT& prj = Prj(); + SEARCH_STACK* search = prj.SchSearchS(); + LIB_PART* part = GetCurPart(); + + if( !part || part->GetDrawItemList().empty() ) + return; + + wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); + if( !default_path ) + default_path = search->LastVisitedPath(); + + wxFileDialog dlg( this, _( "Export Symbol Drawings" ), default_path, + part->GetName(), SchematicSymbolFileWildcard, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + wxFileName fn = dlg.GetPath(); + + /* The GTK file chooser doesn't return the file extension added to + * file name so add it here. */ + if( fn.GetExt().IsEmpty() ) + fn.SetExt( SchematicSymbolFileExtension ); + + prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() ); + + msg.Printf( _( "Saving symbol in '%s'" ), GetChars( fn.GetPath() ) ); + SetStatusText( msg ); + + wxString line; + + // File header + line << wxT( LIBFILE_IDENT ) << wxT( " " ) << LIB_VERSION_MAJOR + << wxT( "." ) << LIB_VERSION_MINOR << wxT( " SYMBOL " ) + << wxT( "Date: " ) << DateAndTime() << wxT( "\n" ); + + // Component name comment and definition. + line << wxT( "# SYMBOL " ) << part->GetName() << wxT( "\n#\nDEF " ) + << part->GetName() << wxT( " " ); + + if( !part->GetReferenceField().GetText().IsEmpty() ) + line << part->GetReferenceField().GetText() << wxT( " " ); + else + line << wxT( "~ " ); + + line << 0 << wxT( " " ) << part->GetPinNameOffset() << wxT( " " ); + + if( part->ShowPinNumbers() ) + line << wxT( "Y " ); + else + line << wxT( "N " ); + + if( part->ShowPinNames() ) + line << wxT( "Y " ); + else + line << wxT( "N " ); + + line << wxT( "1 0 N\n" ); + + try + { + FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() ); + + try + { + formatter.Print( 0, "%s", TO_UTF8( line ) ); + part->GetReferenceField().Save( formatter ); + part->GetValueField().Save( formatter ); + formatter.Print( 0, "DRAW\n" ); + + LIB_ITEMS& drawList = part->GetDrawItemList(); + + BOOST_FOREACH( LIB_ITEM& item, drawList ) + { + if( item.Type() == LIB_FIELD_T ) + continue; + + // Don't save unused parts or alternate body styles. + if( m_unit && item.GetUnit() && ( item.GetUnit() != m_unit ) ) + continue; + + if( m_convert && item.GetConvert() && ( item.GetConvert() != m_convert ) ) + continue; + + item.Save( formatter ); + } + + formatter.Print( 0, "ENDDRAW\n" ); + formatter.Print( 0, "ENDDEF\n" ); + } + catch( const IO_ERROR& ioe ) + { + msg.Printf( _( "An error occurred attempting to save symbol file '%s'" ), + GetChars( fn.GetFullPath() ) ); + DisplayError( this, msg ); + } + } + catch( const IO_ERROR& ioe ) + { + DisplayError( this, ioe.errorText ); + return; + } +} + + +void LIB_EDIT_FRAME::PlaceAnchor() +{ + if( LIB_PART* part = GetCurPart() ) + { + const wxPoint& cross_hair = GetCrossHairPosition(); + + wxPoint offset( -cross_hair.x, cross_hair.y ); + + OnModify( ); + + part->SetOffset( offset ); + + // Redraw the symbol + RedrawScreen( wxPoint( 0 , 0 ), true ); + m_canvas->Refresh(); + } +} diff --git a/eeschema/template_fieldnames.cpp b/eeschema/template_fieldnames.cpp new file mode 100644 index 00000000..28be5dd3 --- /dev/null +++ b/eeschema/template_fieldnames.cpp @@ -0,0 +1,211 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 +#include +#include +#include + +using namespace TFIELD_T; + +const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx ) +{ + // Fixed values for the first few default fields used by EESCHEMA + // (mandatory fields) + switch( aFieldNdx ) + { + case REFERENCE: + return _( "Reference" ); // The component reference, R1, C1, etc. + + case VALUE: + return _( "Value" ); // The component value + name + + case FOOTPRINT: + return _( "Footprint" ); // The footprint for use with Pcbnew + + case DATASHEET: + return _( "Datasheet" ); // Link to a datasheet for component + + default: + break; + } + + // Other fields are use fields, give a default name: + wxString fieldName = _( "Field" ); + fieldName << aFieldNdx; + return fieldName; +} + +void TEMPLATE_FIELDNAME::Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) +{ + out->Print( nestLevel, "(field (name %s)", out->Quotew( m_Name ).c_str() ); + + if( !m_Value.IsEmpty() ) + out->Print( 0, "(value %s)", out->Quotew( m_Value ).c_str() ); + + if( m_Visible ) + out->Print( 0, " visible" ); + + out->Print( 0, ")\n" ); +} + + +void TEMPLATE_FIELDNAME::Parse( TEMPLATE_FIELDNAMES_LEXER* in ) throw( IO_ERROR ) +{ + T tok; + + in->NeedLEFT(); // begin (name ...) + + if( (tok = in->NextTok()) != T_name ) + in->Expecting( T_name ); + + in->NeedSYMBOLorNUMBER(); + + m_Name = FROM_UTF8( in->CurText() ); + + in->NeedRIGHT(); // end (name ...) + + while( (tok = in->NextTok() ) != T_RIGHT && tok != T_EOF ) + { + // "visible" has no '(' prefix, "value" does, so T_LEFT is optional. + if( tok == T_LEFT ) + tok = in->NextTok(); + + switch( tok ) + { + case T_value: + in->NeedSYMBOLorNUMBER(); + m_Value = FROM_UTF8( in->CurText() ); + in->NeedRIGHT(); + break; + + case T_visible: + m_Visible = true; + break; + + default: + in->Expecting( "value|visible" ); + break; + } + } +} + + +void TEMPLATES::Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) +{ + // We'll keep this general, and include the \n, even though the only known + // use at this time will not want the newlines or the indentation. + out->Print( nestLevel, "(templatefields" ); + + for( unsigned i=0; iPrint( 0, ")\n" ); +} + + +void TEMPLATES::Parse( TEMPLATE_FIELDNAMES_LEXER* in ) throw( IO_ERROR ) +{ + T tok; + + while( ( tok = in->NextTok() ) != T_RIGHT && tok != T_EOF ) + { + if( tok == T_LEFT ) + tok = in->NextTok(); + + switch( tok ) + { + case T_templatefields: // a token indicating class TEMPLATES. + + // Be flexible regarding the starting point of the TEMPLATE_FIELDNAMES_LEXER + // stream. Caller may not have read the first two tokens out of the + // stream: T_LEFT and T_templatefields, so ignore them if seen here. + break; + + case T_field: + { + // instantiate on stack, so if exception is thrown, + // destructor runs + TEMPLATE_FIELDNAME field; + + field.Parse( in ); + + // add the field + AddTemplateFieldName( field ); + } + break; + + default: + in->Unexpected( in->CurText() ); + break; + } + } +} + + +int TEMPLATES::AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName ) +{ + // Ensure that the template fieldname does not match a fixed fieldname. + for( int i=0; i + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 _TEMPLATE_FIELDNAME_H_ +#define _TEMPLATE_FIELDNAME_H_ + +#include +#include +#include +#include + +class TEMPLATE_FIELDNAMES_LEXER; + + +/** + * Enum NumFieldType + * is the set of all field indices assuming an array like sequence that a + * SCH_COMPONENT or LIB_PART can hold. + * The first fields are called fixed fields and the quantity of them is + * given by MANDATORY_FIELDS. After that come an unlimited number of + * user defined fields, only some of which have indices defined here. + */ +enum NumFieldType { + REFERENCE = 0, ///< Field Reference of part, i.e. "IC21" + VALUE, ///< Field Value of part, i.e. "3.3K" + FOOTPRINT, ///< Field Name Module PCB, i.e. "16DIP300" + DATASHEET, ///< name of datasheet + + /// The first 4 are mandatory, and must be instantiated in SCH_COMPONENT + /// and LIB_PART constructors + MANDATORY_FIELDS, + + FIELD1 = MANDATORY_FIELDS, + FIELD2, + FIELD3, + FIELD4, + FIELD5, + FIELD6, + FIELD7, + FIELD8 +}; + + +/** + * Struct TEMPLATE_FIELDNAME + * holds a name of a component's field, field value, and default visibility. + * Template fieldnames are wanted fieldnames for use in the symbol/component + * property editors. + */ +struct TEMPLATE_FIELDNAME +{ + wxString m_Name; ///< The field name + wxString m_Value; ///< The default value or empty + bool m_Visible; ///< If first appearance of the field's editor has as visible. + + TEMPLATE_FIELDNAME() : + m_Visible( false ) + { + } + + TEMPLATE_FIELDNAME( const wxString& aName ) : + m_Name( aName ), + m_Visible( false ) + { + } + + TEMPLATE_FIELDNAME( const TEMPLATE_FIELDNAME& ref ) + { + m_Name = ref.m_Name; + m_Value = ref.m_Value; + m_Visible = ref.m_Visible; + } + + /** + * Function Format + * serializes this object out as text into the given OUTPUTFORMATTER. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); + + /** + * Function Parse + * fills this object from information in the input stream \a aSpec, which + * is a TEMPLATE_FIELDNAMES_LEXER. The entire textual element spec is
      + * (field (name _yourfieldname_)(value _yourvalue_) visible))
      + * The presence of value is optional, the presence of visible is optional. + * When this function is called, the input token stream given by \a aSpec + * is assumed to be positioned at the '^' in the following example, i.e. just after the + * identifying keyword and before the content specifying stuff.
      + * (field ^ (....) ) + * + * @param aSpec is the input token stream of keywords and symbols. + */ + void Parse( TEMPLATE_FIELDNAMES_LEXER* aSpec ) throw( IO_ERROR ); + + /** + * Function GetDefaultFieldName + * returns a default symbol field name for field \a aFieldNdx for all components. + * These fieldnames are not modifiable, but template fieldnames are. + * @param aFieldNdx The field number index, > 0 + */ + static const wxString GetDefaultFieldName( int aFieldNdx ); +}; + +typedef std::vector< TEMPLATE_FIELDNAME > TEMPLATE_FIELDNAMES; + + +class TEMPLATES +{ +private: + TEMPLATE_FIELDNAMES m_Fields; + +public: + + /** + * Function Format + * serializes this object out as text into the given OUTPUTFORMATTER. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); + + /** + * Function Parse + * fills this object from information in the input stream handled by TEMPLATE_FIELDNAMES_LEXER + */ + void Parse( TEMPLATE_FIELDNAMES_LEXER* in ) throw( IO_ERROR ); + + + /** + * Function AddTemplateFieldName + * inserts or appends a wanted symbol field name into the fieldnames + * template. Should be used for any symbol property editor. If the name + * already exists, it overwrites the same name. + * + * @param aFieldName is a full description of the wanted field, and it must not match + * any of the default fieldnames. + * @return int - the index within the config container at which aFieldName was + * added, or -1 if the name is illegal because it matches a default fieldname. + */ + int AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName ); + + /** + * Function DeleteAllTemplateFieldNames + * deletes the entire contents. + */ + void DeleteAllTemplateFieldNames() + { + m_Fields.clear(); + } + + /** + * Function GetTemplateFieldName + * returns a template fieldnames list for read only access. + */ + const TEMPLATE_FIELDNAMES& GetTemplateFieldNames() + { + return m_Fields; + } + + /** + * Function HasFieldName + * checks for \a aName in the the template field name list. + * + * @param aName A wxString object containing the field name to search for. + * @return True if \a aName is found in the list. + */ + bool HasFieldName( const wxString& aName ) const; +}; + +#endif // _TEMPLATE_FIELDNAME_H_ diff --git a/eeschema/template_fieldnames.keywords b/eeschema/template_fieldnames.keywords new file mode 100644 index 00000000..acd44688 --- /dev/null +++ b/eeschema/template_fieldnames.keywords @@ -0,0 +1,5 @@ +field +name +templatefields +value +visible diff --git a/eeschema/tool_lib.cpp b/eeschema/tool_lib.cpp new file mode 100644 index 00000000..729b7688 --- /dev/null +++ b/eeschema/tool_lib.cpp @@ -0,0 +1,243 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file tool_lib.cpp + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef __UNIX__ +#define LISTBOX_WIDTH 140 +#else +#define LISTBOX_WIDTH 120 +#endif + + +extern int ExportPartId; +extern int ImportPartId; +extern int CreateNewLibAndSavePartId; + + +void LIB_EDIT_FRAME::ReCreateVToolbar() +{ + if( m_drawToolBar != NULL ) + return; + + m_drawToolBar = new wxAuiToolBar( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_VERTICAL ); + + // Set up toolbar + m_drawToolBar->AddTool( ID_NO_TOOL_SELECTED, wxEmptyString, KiBitmap( cursor_xpm ), + _( "Deselect current tool" ), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_PIN_BUTT, wxEmptyString, KiBitmap( pin_xpm ), + HELP_ADD_PIN, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_BODY_TEXT_BUTT, wxEmptyString, KiBitmap( add_text_xpm ), + HELP_ADD_BODYTEXT, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_BODY_RECT_BUTT, wxEmptyString, KiBitmap( add_rectangle_xpm ), + HELP_ADD_BODYRECT, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_BODY_CIRCLE_BUTT, wxEmptyString, KiBitmap( add_circle_xpm ), + HELP_ADD_BODYCIRCLE, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_BODY_ARC_BUTT, wxEmptyString, KiBitmap( add_arc_xpm ), + HELP_ADD_BODYARC, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_BODY_LINE_BUTT, wxEmptyString, KiBitmap( add_polygon_xpm ), + HELP_ADD_BODYPOLYGON, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_ANCHOR_ITEM_BUTT, wxEmptyString, KiBitmap( anchor_xpm ), + _( "Move part anchor" ), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_IMPORT_BODY_BUTT, wxEmptyString, KiBitmap( import_xpm ), + _( "Import existing drawings" ), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_EXPORT_BODY_BUTT, wxEmptyString, KiBitmap( export_xpm ), + _( "Export current drawing" ), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LIBEDIT_DELETE_ITEM_BUTT, wxEmptyString, KiBitmap( delete_xpm ), + HELP_DELETE_ITEMS, wxITEM_CHECK ); + + m_drawToolBar->Realize(); +} + + +void LIB_EDIT_FRAME::ReCreateHToolbar() +{ + wxString msg; + + // Create the toolbar if not exists + if( m_mainToolBar != NULL ) + return; + + m_mainToolBar = new wxAuiToolBar( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_HORZ_LAYOUT ); + + // Set up toolbar + m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_CURRENT_LIB, wxEmptyString, + KiBitmap( save_library_xpm ), + _( "Save current library to disk" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_SELECT_CURRENT_LIB, wxEmptyString, KiBitmap( library_xpm ), + _( "Select working library" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_DELETE_PART, wxEmptyString, KiBitmap( delete_xpm ), + _( "Delete component in current library" ) ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_TO_LIBVIEW, wxEmptyString, KiBitmap( library_browse_xpm ), + HELP_RUN_LIB_VIEWER ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBEDIT_NEW_PART, wxEmptyString, KiBitmap( new_component_xpm ), + _( "Create a new component" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_SELECT_PART, wxEmptyString, + KiBitmap( import_cmp_from_lib_xpm ), + _( "Load component to edit from the current library" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_NEW_PART_FROM_EXISTING, wxEmptyString, + KiBitmap( copycomponent_xpm ), + _( "Create a new component from the current one" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_CURRENT_PART, wxEmptyString, + KiBitmap( save_part_in_mem_xpm ), + _( "Update current component in current library" ) ); + + m_mainToolBar->AddTool( ImportPartId, wxEmptyString, KiBitmap( import_xpm ), + _( "Import component" ) ); + + m_mainToolBar->AddTool( ExportPartId, wxEmptyString, KiBitmap( export_xpm ), + _( "Export component" ) ); + + m_mainToolBar->AddTool( CreateNewLibAndSavePartId, wxEmptyString, KiBitmap( new_library_xpm ), + _( "Save current component to new library" ) ); + + m_mainToolBar->AddSeparator(); + msg = AddHotkeyName( _( "Undo last command" ), g_Libedit_Hokeys_Descr, HK_UNDO, IS_COMMENT ); + m_mainToolBar->AddTool( wxID_UNDO, wxEmptyString, KiBitmap( undo_xpm ), msg ); + msg = AddHotkeyName( _( "Redo the last command" ), g_Libedit_Hokeys_Descr, HK_REDO, + IS_COMMENT ); + m_mainToolBar->AddTool( wxID_REDO, wxEmptyString, KiBitmap( redo_xpm ), msg ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBEDIT_GET_FRAME_EDIT_PART, wxEmptyString, + KiBitmap( part_properties_xpm ), _( "Edit component properties" ) ); + + m_mainToolBar->AddTool( ID_LIBEDIT_GET_FRAME_EDIT_FIELDS, wxEmptyString, + KiBitmap( add_text_xpm ), + _( "Add and remove fields and edit field properties" ) ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBEDIT_CHECK_PART, wxEmptyString, KiBitmap( erc_xpm ), + _( "Test for duplicate and off grid pins" ) ); + + m_mainToolBar->AddSeparator(); + msg = AddHotkeyName( HELP_ZOOM_IN, g_Libedit_Hokeys_Descr, HK_ZOOM_IN, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_IN, wxEmptyString, KiBitmap( zoom_in_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_OUT, g_Libedit_Hokeys_Descr, HK_ZOOM_OUT, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_OUT, wxEmptyString, KiBitmap( zoom_out_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_REDRAW, g_Libedit_Hokeys_Descr, HK_ZOOM_REDRAW, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_REDRAW, wxEmptyString, KiBitmap( zoom_redraw_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_FIT, g_Libedit_Hokeys_Descr, HK_ZOOM_AUTO, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_PAGE, wxEmptyString, KiBitmap( zoom_fit_in_page_xpm ), msg ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_DE_MORGAN_NORMAL_BUTT, wxEmptyString, KiBitmap( morgan1_xpm ), + _( "Show as \"De Morgan\" normal part" ), wxITEM_CHECK ); + m_mainToolBar->AddTool( ID_DE_MORGAN_CONVERT_BUTT, wxEmptyString, KiBitmap( morgan2_xpm ), + _( "Show as \"De Morgan\" convert part" ), wxITEM_CHECK ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBEDIT_VIEW_DOC, wxEmptyString, KiBitmap( datasheet_xpm ), + _( "Show the associated datasheet or document" ) ); + + m_mainToolBar->AddSeparator(); + m_partSelectBox = new wxComboBox( m_mainToolBar, + ID_LIBEDIT_SELECT_PART_NUMBER, + wxEmptyString, + wxDefaultPosition, + wxSize( LISTBOX_WIDTH, -1 ), + 0, NULL, wxCB_READONLY ); + m_mainToolBar->AddControl( m_partSelectBox ); + + m_aliasSelectBox = new wxComboBox( m_mainToolBar, + ID_LIBEDIT_SELECT_ALIAS, + wxEmptyString, + wxDefaultPosition, + wxSize( LISTBOX_WIDTH, -1 ), + 0, NULL, wxCB_READONLY ); + m_mainToolBar->AddControl( m_aliasSelectBox ); + + m_mainToolBar->AddSeparator(); + msg = _( "Edit pins per part or body style (Use carefully!)" ); + m_mainToolBar->AddTool( ID_LIBEDIT_EDIT_PIN_BY_PIN, wxEmptyString, KiBitmap( pin2pin_xpm ), + msg, wxITEM_CHECK ); + m_mainToolBar->AddTool( ID_LIBEDIT_EDIT_PIN_BY_TABLE, wxEmptyString, KiBitmap( pin_table_xpm ), + _( "Show pin table" ) ); + + // after adding the buttons to the toolbar, must call Realize() to reflect the changes + m_mainToolBar->Realize(); +} + + +void LIB_EDIT_FRAME::CreateOptionToolbar() +{ + if( m_optionsToolBar ) + return; + + m_optionsToolBar = new wxAuiToolBar( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_VERTICAL ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SHOW_GRID, wxEmptyString, KiBitmap( grid_xpm ), + _( "Turn grid off" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_UNIT_INCH, wxEmptyString, + KiBitmap( unit_inch_xpm ), _( "Units in inches" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_UNIT_MM, wxEmptyString, + KiBitmap( unit_mm_xpm ), + _( "Units in millimeters" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_CURSOR, wxEmptyString, + KiBitmap( cursor_shape_xpm ), + _( "Change cursor shape" ), wxITEM_CHECK ); + + m_optionsToolBar->Realize(); +} diff --git a/eeschema/tool_sch.cpp b/eeschema/tool_sch.cpp new file mode 100644 index 00000000..314313c0 --- /dev/null +++ b/eeschema/tool_sch.cpp @@ -0,0 +1,325 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2017 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 + */ + +/** + * @file tool_sch.cpp + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + + +/* Create the main Horizontal Toolbar for the schematic editor + */ +void SCH_EDIT_FRAME::ReCreateHToolbar() +{ + if( m_mainToolBar != NULL ) + return; + + wxString msg; + m_mainToolBar = new wxAuiToolBar( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_HORZ_LAYOUT ); + + // Set up toolbar + if( Kiface().IsSingle() ) // not when under a project mgr + { + // These 2 menus have meaning only outside a project, i.e. not under a project manager: + m_mainToolBar->AddTool( ID_NEW_PROJECT, wxEmptyString, KiBitmap( new_sch_xpm ), + _( "New schematic project" ) ); + + m_mainToolBar->AddTool( ID_LOAD_PROJECT, wxEmptyString, KiBitmap( open_document_xpm ), + _( "Open schematic project" ) ); + } + + m_mainToolBar->AddTool( ID_SAVE_PROJECT, wxEmptyString, KiBitmap( save_project_xpm ), + _( "Save schematic project" ) ); + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( ID_SHEET_SET, wxEmptyString, KiBitmap( sheetset_xpm ), + _( "Page settings" ) ); + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( wxID_PRINT, wxEmptyString, KiBitmap( print_button_xpm ), + _( "Print schematic" ) ); + + m_mainToolBar->AddTool( ID_GEN_PLOT_SCHEMATIC, wxEmptyString, KiBitmap( plot_xpm ), + _( "Plot schematic" ) ); + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( wxID_CUT, wxEmptyString, KiBitmap( cut_button_xpm ), + _( "Cut selected item" ) ); + + m_mainToolBar->AddTool( wxID_COPY, wxEmptyString, KiBitmap( copy_button_xpm ), + _( "Copy selected item" ) ); + + m_mainToolBar->AddTool( wxID_PASTE, wxEmptyString, KiBitmap( paste_xpm ), + _( "Paste" ) ); + + + m_mainToolBar->AddSeparator(); + + msg = AddHotkeyName( HELP_UNDO, g_Schematic_Hokeys_Descr, HK_UNDO, IS_COMMENT ); + m_mainToolBar->AddTool( wxID_UNDO, wxEmptyString, KiBitmap( undo_xpm ), msg ); + + msg = AddHotkeyName( HELP_REDO, g_Schematic_Hokeys_Descr, HK_REDO, IS_COMMENT ); + m_mainToolBar->AddTool( wxID_REDO, wxEmptyString, KiBitmap( redo_xpm ), msg ); + + + m_mainToolBar->AddSeparator(); + + msg = AddHotkeyName( HELP_FIND, g_Schematic_Hokeys_Descr, HK_FIND_ITEM, IS_COMMENT ); + m_mainToolBar->AddTool( ID_FIND_ITEMS, wxEmptyString, KiBitmap( find_xpm ), msg ); + + m_mainToolBar->AddTool( wxID_REPLACE, wxEmptyString, KiBitmap( find_replace_xpm ), + wxNullBitmap, wxITEM_NORMAL, _( "Find and replace text" ), + HELP_REPLACE, NULL ); + + + m_mainToolBar->AddSeparator(); + + msg = AddHotkeyName( HELP_ZOOM_IN, g_Schematic_Hokeys_Descr, HK_ZOOM_IN, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_IN, wxEmptyString, KiBitmap( zoom_in_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_OUT, g_Schematic_Hokeys_Descr, HK_ZOOM_OUT, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_OUT, wxEmptyString, KiBitmap( zoom_out_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_REDRAW, g_Schematic_Hokeys_Descr, HK_ZOOM_REDRAW, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_REDRAW, wxEmptyString, KiBitmap( zoom_redraw_xpm ), msg ); + + msg = AddHotkeyName( HELP_ZOOM_FIT, g_Schematic_Hokeys_Descr, HK_ZOOM_AUTO, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_PAGE, wxEmptyString, KiBitmap( zoom_fit_in_page_xpm ), msg ); + + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( ID_HIERARCHY, wxEmptyString, KiBitmap( hierarchy_nav_xpm ), + _( "Navigate schematic hierarchy" ) ); + + + m_mainToolBar->AddTool( ID_POPUP_SCH_LEAVE_SHEET, wxEmptyString, KiBitmap( leave_sheet_xpm ), + _( "Leave sheet" ) ); + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( ID_RUN_LIBRARY, wxEmptyString, KiBitmap( libedit_xpm ), + HELP_RUN_LIB_EDITOR ); + + m_mainToolBar->AddTool( ID_TO_LIBVIEW, wxEmptyString, KiBitmap( library_browse_xpm ), + HELP_RUN_LIB_VIEWER ); + + // modedit is with libedit in a "library section" because the user must have footprints before + // they can be assigned. + m_mainToolBar->AddTool( ID_RUN_PCB_MODULE_EDITOR, wxEmptyString, KiBitmap( module_editor_xpm ), + _( "Footprint Editor" ) ); + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( ID_GET_ANNOTATE, wxEmptyString, KiBitmap( annotate_xpm ), + HELP_ANNOTATE ); + + m_mainToolBar->AddTool( ID_GET_ERC, wxEmptyString, KiBitmap( erc_xpm ), + _( "Perform electrical rules check" ) ); + + m_mainToolBar->AddTool( ID_RUN_CVPCB, wxEmptyString, KiBitmap( cvpcb_xpm ), + _( "Run CvPcb to associate components and footprints" ) ); + + m_mainToolBar->AddTool( ID_GET_NETLIST, wxEmptyString, KiBitmap( netlist_xpm ), + _( "Generate netlist" ) ); + + m_mainToolBar->AddTool( ID_GET_TOOLS, wxEmptyString, KiBitmap( bom_xpm ), + HELP_GENERATE_BOM ); + + + m_mainToolBar->AddSeparator(); + + m_mainToolBar->AddTool( ID_RUN_PCB, wxEmptyString, KiBitmap( pcbnew_xpm ), + _( "Run Pcbnew to layout printed circuit board" ) ); + + m_mainToolBar->AddTool( ID_BACKANNO_ITEMS, wxEmptyString, + KiBitmap( import_footprint_names_xpm ), + HELP_IMPORT_FOOTPRINTS ); + + // after adding the tools to the toolbar, must call Realize() to reflect the changes + m_mainToolBar->Realize(); +} + + +/* Create Vertical Right Toolbar + */ +void SCH_EDIT_FRAME::ReCreateVToolbar() +{ + if( m_drawToolBar ) + return; + + m_drawToolBar = new wxAuiToolBar( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_VERTICAL ); + + // Set up toolbar + m_drawToolBar->AddTool( ID_NO_TOOL_SELECTED, wxEmptyString, KiBitmap( cursor_xpm ), + wxEmptyString, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_HIERARCHY_PUSH_POP_BUTT, wxEmptyString, + KiBitmap( hierarchy_cursor_xpm ), + _( "Ascend/descend hierarchy" ), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_SCH_PLACE_COMPONENT, wxEmptyString, KiBitmap( add_component_xpm ), + HELP_PLACE_COMPONENTS, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_PLACE_POWER_BUTT, wxEmptyString, KiBitmap( add_power_xpm ), + HELP_PLACE_POWERPORT, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_WIRE_BUTT, wxEmptyString, KiBitmap( add_line_xpm ), + HELP_PLACE_WIRE, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_BUS_BUTT, wxEmptyString, KiBitmap( add_bus_xpm ), + HELP_PLACE_BUS, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_WIRETOBUS_ENTRY_BUTT, wxEmptyString, KiBitmap( add_line2bus_xpm ), + HELP_PLACE_WIRE2BUS_ENTRY, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_BUSTOBUS_ENTRY_BUTT, wxEmptyString, KiBitmap( add_bus2bus_xpm ), + HELP_PLACE_BUS2BUS_ENTRY, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_NOCONN_BUTT, wxEmptyString, KiBitmap( noconn_xpm ), + HELP_PLACE_NC_FLAG, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_JUNCTION_BUTT, wxEmptyString, KiBitmap( add_junction_xpm ), + HELP_PLACE_JUNCTION, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LABEL_BUTT, wxEmptyString, KiBitmap( add_line_label_xpm ), + HELP_PLACE_NETLABEL, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_GLABEL_BUTT, wxEmptyString, KiBitmap( add_glabel_xpm ), + HELP_PLACE_GLOBALLABEL, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_HIERLABEL_BUTT, wxEmptyString, + KiBitmap( add_hierarchical_label_xpm ), + HELP_PLACE_HIER_LABEL, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_SHEET_SYMBOL_BUTT, wxEmptyString, + KiBitmap( add_hierarchical_subsheet_xpm ), + HELP_PLACE_SHEET, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_IMPORT_HLABEL_BUTT, wxEmptyString, + KiBitmap( import_hierarchical_label_xpm ), + HELP_IMPORT_SHEETPIN, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_SHEET_PIN_BUTT, wxEmptyString, + KiBitmap( add_hierar_pin_xpm ), + HELP_PLACE_SHEETPIN, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_LINE_COMMENT_BUTT, wxEmptyString, + KiBitmap( add_dashed_line_xpm ), + HELP_PLACE_GRAPHICLINES, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_TEXT_COMMENT_BUTT, wxEmptyString, KiBitmap( add_text_xpm ), + HELP_PLACE_GRAPHICTEXTS, wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_ADD_IMAGE_BUTT, wxEmptyString, KiBitmap( image_xpm ), + _("Add bitmap image"), wxITEM_CHECK ); + + m_drawToolBar->AddTool( ID_SCHEMATIC_DELETE_ITEM_BUTT, wxEmptyString, + KiBitmap( delete_xpm ), + HELP_DELETE_ITEMS, wxITEM_CHECK ); + + m_drawToolBar->Realize(); +} + + +/* Create Vertical Left Toolbar (Option Toolbar) + */ +void SCH_EDIT_FRAME::ReCreateOptToolbar() +{ + if( m_optionsToolBar ) + return; + + m_optionsToolBar = new wxAuiToolBar( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_VERTICAL ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SHOW_GRID, wxEmptyString, + KiBitmap( grid_xpm ), + _( "Turn grid off" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_UNIT_INCH, wxEmptyString, + KiBitmap( unit_inch_xpm ), + _( "Set unit to inch" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_UNIT_MM, wxEmptyString, + KiBitmap( unit_mm_xpm ), + _( "Set unit to mm" ), wxITEM_CHECK ); + + m_optionsToolBar->AddTool( ID_TB_OPTIONS_SELECT_CURSOR, wxEmptyString, + KiBitmap( cursor_shape_xpm ), + _( "Change cursor shape" ), wxITEM_CHECK ); + + //m_optionsToolBar->AddSeparator(); + m_optionsToolBar->AddTool( ID_TB_OPTIONS_HIDDEN_PINS, wxEmptyString, + KiBitmap( hidden_pin_xpm ), + _( "Show hidden pins" ), wxITEM_CHECK ); + + //m_optionsToolBar->AddSeparator(); + m_optionsToolBar->AddTool( ID_TB_OPTIONS_BUS_WIRES_ORIENT, wxEmptyString, + KiBitmap( lines90_xpm ), + _( "HV orientation for wires and bus" ), + wxITEM_CHECK ); + + m_optionsToolBar->Realize(); +} + + +void SCH_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event ) +{ + if( m_canvas == NULL ) + return; + + int id = event.GetId(); + + switch( id ) + { + case ID_TB_OPTIONS_HIDDEN_PINS: + m_showAllPins = m_optionsToolBar->GetToolToggled( id ); + m_canvas->Refresh(); + break; + + case ID_TB_OPTIONS_BUS_WIRES_ORIENT: + SetForceHVLines( m_optionsToolBar->GetToolToggled( id ) ); + break; + + default: + wxFAIL_MSG( wxT( "Unexpected select option tool bar ID." ) ); + break; + } +} diff --git a/eeschema/tool_viewlib.cpp b/eeschema/tool_viewlib.cpp new file mode 100644 index 00000000..79a50bdb --- /dev/null +++ b/eeschema/tool_viewlib.cpp @@ -0,0 +1,279 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2011 KiCad Developers, see change_log.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 + */ + +/** + * @file tool_viewlib.cpp + * @brief Build the toolbars for the library browser. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +void LIB_VIEW_FRAME::ReCreateHToolbar() +{ + wxString msg; + LIB_ALIAS* entry = NULL; + bool asdeMorgan = false; + LIB_PART* part = NULL; + + if( m_mainToolBar == NULL ) + { + m_mainToolBar = new wxAuiToolBar( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_HORZ_LAYOUT ); + + // Set up toolbar + m_mainToolBar->AddTool( ID_LIBVIEW_SELECT_LIB, wxEmptyString, + KiBitmap( library_xpm ), + _( "Select library to browse" ) ); + + m_mainToolBar->AddTool( ID_LIBVIEW_SELECT_PART, wxEmptyString, + KiBitmap( add_component_xpm ), + _( "Select component to browse" ) ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBVIEW_PREVIOUS, wxEmptyString, + KiBitmap( lib_previous_xpm ), + _( "Display previous component" ) ); + + m_mainToolBar->AddTool( ID_LIBVIEW_NEXT, wxEmptyString, + KiBitmap( lib_next_xpm ), + _( "Display next component" ) ); + + m_mainToolBar->AddSeparator(); + msg = AddHotkeyName( _( "Zoom in" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_IN, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_IN, wxEmptyString, + KiBitmap( zoom_in_xpm ), msg ); + + msg = AddHotkeyName( _( "Zoom out" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_OUT, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_OUT, wxEmptyString, + KiBitmap( zoom_out_xpm ), msg ); + + msg = AddHotkeyName( _( "Redraw view" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_REDRAW, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_REDRAW, wxEmptyString, + KiBitmap( zoom_redraw_xpm ), msg ); + + msg = AddHotkeyName( _( "Zoom auto" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_AUTO, IS_COMMENT ); + m_mainToolBar->AddTool( ID_ZOOM_PAGE, wxEmptyString, + KiBitmap( zoom_fit_in_page_xpm ), msg ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, wxEmptyString, + KiBitmap( morgan1_xpm ), + _( "Show as \"De Morgan\" normal part" ), + wxITEM_CHECK ); + + m_mainToolBar->AddTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, wxEmptyString, + KiBitmap( morgan2_xpm ), + _( "Show as \"De Morgan\" convert part" ), + wxITEM_CHECK ); + + m_mainToolBar->AddSeparator(); + + m_selpartBox = new wxComboBox( m_mainToolBar, ID_LIBVIEW_SELECT_PART_NUMBER, + wxEmptyString, wxDefaultPosition, + wxSize( 150, -1 ), 0, NULL, wxCB_READONLY ); + m_mainToolBar->AddControl( m_selpartBox ); + + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBVIEW_VIEWDOC, wxEmptyString, + KiBitmap( datasheet_xpm ), + _( "View component documents" ) ); + m_mainToolBar->EnableTool( ID_LIBVIEW_VIEWDOC, false ); + + if( IsModal() ) + { + m_mainToolBar->AddSeparator(); + m_mainToolBar->AddTool( ID_LIBVIEW_CMP_EXPORT_TO_SCHEMATIC, + wxEmptyString, KiBitmap( export_xpm ), + _( "Insert component in schematic" ) ); + } + + // after adding the buttons to the toolbar, must call Realize() to + // reflect the changes + m_mainToolBar->Realize(); + } + + if( m_libraryName.size() && m_entryName.size() ) + { + if( PART_LIB* lib = Prj().SchLibs()->FindLibrary( m_libraryName ) ) + { + part = lib->FindPart( m_entryName ); + + if( part && part->HasConversion() ) + asdeMorgan = true; + + entry = lib->FindEntry( m_entryName ); + } + } + + // Must be AFTER Realize(): + m_mainToolBar->EnableTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, asdeMorgan ); + m_mainToolBar->EnableTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, asdeMorgan ); + + if( asdeMorgan ) + { + bool normal = m_convert <= 1; + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT,normal ); + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, !normal ); + } + else + { + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, true ); + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, false ); + } + + int parts_count = 1; + + if( part ) + parts_count = std::max( part->GetUnitCount(), 1 ); + + m_selpartBox->Clear(); + + for( int ii = 0; ii < parts_count; ii++ ) + { + wxString msg = wxString::Format( _( "Unit %c" ), 'A' + ii ); + m_selpartBox->Append( msg ); + } + + m_selpartBox->SetSelection( m_unit > 0 ? m_unit - 1 : 0 ); + m_selpartBox->Enable( parts_count > 1 ); + + m_mainToolBar->EnableTool( ID_LIBVIEW_VIEWDOC, entry && !!entry->GetDocFileName() ); + + m_mainToolBar->Refresh(); +} + + +void LIB_VIEW_FRAME::ReCreateVToolbar() +{ +} + + +// Virtual function +void LIB_VIEW_FRAME::ReCreateMenuBar( void ) +{ + // Create and try to get the current menubar + wxMenuBar* menuBar = GetMenuBar(); + + if( !menuBar ) + menuBar = new wxMenuBar(); + + // Delete all existing menus so they can be rebuilt. + // This allows language changes of the menu text on the fly. + menuBar->Freeze(); + + while( menuBar->GetMenuCount() ) + delete menuBar->Remove( 0 ); + + // Recreate all menus: + wxString text; + + // Menu File: + wxMenu* fileMenu = new wxMenu; + + // Active library selection + AddMenuItem( fileMenu, ID_LIBVIEW_SELECT_LIB, _("Set Current Library"), + _( "Select library to be displayed" ), + KiBitmap( open_library_xpm ) ); + fileMenu->AppendSeparator(); + + // Close viewer + AddMenuItem( fileMenu, wxID_EXIT, + _( "Cl&ose" ), + _( "Close schematic component viewer" ), + KiBitmap( exit_xpm ) ); + + // View menu + wxMenu* viewMenu = new wxMenu; + + text = AddHotkeyName( _( "Zoom &In" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_IN, IS_ACCELERATOR ); + AddMenuItem( viewMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) ); + + text = AddHotkeyName( _( "Zoom &Out" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_OUT, IS_ACCELERATOR ); + AddMenuItem( viewMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) ); + + text = AddHotkeyName( _( "&Fit on Screen" ), g_Viewlib_Hokeys_Descr, + HK_ZOOM_AUTO ); + AddMenuItem( viewMenu, ID_ZOOM_PAGE, text, HELP_ZOOM_FIT, + KiBitmap( zoom_fit_in_page_xpm ) ); + + text = AddHotkeyName( _( "&Redraw" ), g_Viewlib_Hokeys_Descr, HK_ZOOM_REDRAW ); + AddMenuItem( viewMenu, ID_ZOOM_REDRAW, text, + HELP_ZOOM_REDRAW, KiBitmap( zoom_redraw_xpm ) ); + + // Menu Help: + wxMenu* helpMenu = new wxMenu; + + // Version info + AddHelpVersionInfoMenuEntry( helpMenu ); + + // Contents + AddMenuItem( helpMenu, wxID_HELP, + _( "Eeschema &Manual" ), + _( "Open Eeschema manual" ), + KiBitmap( online_help_xpm ) ); + + AddMenuItem( helpMenu, wxID_INDEX, + _( "&Getting Started in KiCad" ), + _( "Open the \"Getting Started in KiCad\" guide for beginners" ), + KiBitmap( help_xpm ) ); + + // About Pcbnew + helpMenu->AppendSeparator(); + AddMenuItem( helpMenu, wxID_ABOUT, + _( "&About Eeschema" ), + _( "About Eeschema schematic designer" ), + KiBitmap( info_xpm ) ); + + // Append menus to the menubar + menuBar->Append( fileMenu, _( "&File" ) ); + + menuBar->Append( viewMenu, _( "&View" ) ); + menuBar->Append( helpMenu, _( "&Help" ) ); + + menuBar->Thaw(); + + // Associate the menu bar with the frame, if no previous menubar + if( GetMenuBar() == NULL ) + SetMenuBar( menuBar ); + else + menuBar->Refresh(); +} diff --git a/eeschema/transform.cpp b/eeschema/transform.cpp new file mode 100644 index 00000000..53aac2d0 --- /dev/null +++ b/eeschema/transform.cpp @@ -0,0 +1,148 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 Wayne Stambaugh + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 +#include +#include +#include +#include + + +TRANSFORM& TRANSFORM::operator=( const TRANSFORM& aTransform ) +{ + if( this == &aTransform ) // Check for self assingnemt; + return *this; + + x1 = aTransform.x1; + y1 = aTransform.y1; + x2 = aTransform.x2; + y2 = aTransform.y2; + return *this; +} + + +bool TRANSFORM::operator==( const TRANSFORM& aTransform ) const +{ + return ( x1 == aTransform.x1 && + y1 == aTransform.y1 && + x2 == aTransform.x2 && + y2 == aTransform.y2 ); +} + + +wxPoint TRANSFORM::TransformCoordinate( const wxPoint& aPoint ) const +{ + return wxPoint( ( x1 * aPoint.x ) + ( y1 * aPoint.y ), + ( x2 * aPoint.x ) + ( y2 * aPoint.y ) ); +} + +EDA_RECT TRANSFORM::TransformCoordinate( const EDA_RECT& aRect ) const +{ + EDA_RECT rect; + rect.SetOrigin( TransformCoordinate( aRect.GetOrigin() ) ); + rect.SetEnd( TransformCoordinate( aRect.GetEnd() ) ); + return rect; +} + +/* +* Calculate the Inverse mirror/rotation transform. +*/ +TRANSFORM TRANSFORM::InverseTransform( ) const +{ + int invx1; + int invx2; + int invy1; + int invy2; + + /* Calculates the inverse matrix coeffs: + * for a matrix m{x1, x2, y1, y2} + * the inverse matrix is 1/(x1*y2 -x2*y1) m{y2,-x2,-y1,x1) + */ + int det = x1*y2 -x2*y1; // Is never null, because the inverse matrix exists + invx1 = y2/det; + invx2 = -x2/det; + invy1 = -y1/det; + invy2 = x1/det; + + TRANSFORM invtransform( invx1, invy1, invx2, invy2 ); + return invtransform; +} + + +bool TRANSFORM::MapAngles( int* aAngle1, int* aAngle2 ) const +{ + wxCHECK_MSG( aAngle1 != NULL && aAngle2 != NULL, false, + wxT( "Cannot map NULL point angles." ) ); + + int Angle, Delta; + double x, y, t; + bool swap = false; + + Delta = *aAngle2 - *aAngle1; + if( Delta >= 1800 ) + { + *aAngle1 -= 1; + *aAngle2 += 1; + } + + x = cos( DECIDEG2RAD( *aAngle1 ) ); + y = sin( DECIDEG2RAD( *aAngle1 ) ); + t = x * x1 + y * y1; + y = x * x2 + y * y2; + x = t; + *aAngle1 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) ); + + x = cos( DECIDEG2RAD( *aAngle2 ) ); + y = sin( DECIDEG2RAD( *aAngle2 ) ); + t = x * x1 + y * y1; + y = x * x2 + y * y2; + x = t; + *aAngle2 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) ); + + NORMALIZE_ANGLE_POS( *aAngle1 ); + NORMALIZE_ANGLE_POS( *aAngle2 ); + if( *aAngle2 < *aAngle1 ) + *aAngle2 += 3600; + + if( *aAngle2 - *aAngle1 > 1800 ) // Need to swap the two angles + { + Angle = (*aAngle1); + *aAngle1 = (*aAngle2); + *aAngle2 = Angle; + + NORMALIZE_ANGLE_POS( *aAngle1 ); + NORMALIZE_ANGLE_POS( *aAngle2 ); + if( *aAngle2 < *aAngle1 ) + *aAngle2 += 3600; + swap = true; + } + + if( Delta >= 1800 ) + { + *aAngle1 += 1; + *aAngle2 -= 1; + } + + return swap; +} diff --git a/eeschema/transform.h b/eeschema/transform.h new file mode 100644 index 00000000..7d220e0c --- /dev/null +++ b/eeschema/transform.h @@ -0,0 +1,106 @@ +/** + * @file transform.h + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007-2010 Wayne Stambaugh + * Copyright (C) 2007 KiCad Developers, see change_log.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 _TRANSFORM_H_ +#define _TRANSFORM_H_ + +#include + +class EDA_RECT; + +/** + * Class for tranforming drawing coordinates for a wxDC device context. + * + * This probably should be a base class with all pure methods and a derived class + * named WXDC_TRANFORM be created. Then in the future if some new device context + * is used, a new transform could be derived from the base class and all the drawable + * objects would have to do is provide overloaded draw methods to use the new transorm. + */ +class TRANSFORM +{ +public: + int x1; + int y1; + int x2; + int y2; + + /** + * The default construct creates a tranform that draws object is the normal orientation. + */ + TRANSFORM() : x1( 1 ), y1( 0 ), x2( 0 ), y2( -1 ) {} + + TRANSFORM( int x1, int y1, int x2, int y2 ) : x1( x1 ), y1( y1 ), x2( x2 ), y2( y2 ) {} + + TRANSFORM& operator=( const TRANSFORM& aTransform ); + + bool operator==( const TRANSFORM& aTransform ) const; + + bool operator!=( const TRANSFORM& aTransform ) const { return !( *this == aTransform ); } + + /** + * Calculate a new coordinate according to the mirror/rotation transform. + * Useful to calculate actual coordinates of a point + * from coordinates relative to a component + * which are given for a non rotated, non mirrored item + * @param aPoint = The position to transform + * @return The transformed coordinate. + */ + wxPoint TransformCoordinate( const wxPoint& aPoint ) const; + + /** + * Calculate a new rect according to the mirror/rotation transform. + * Useful to calculate actual coordinates of a point + * from coordinates relative to a component + * which are given for a non rotated, non mirrored item + * @param aRect = The rectangle to transform + * @return The transformed rectangle. + */ + EDA_RECT TransformCoordinate( const EDA_RECT& aRect ) const; + + /** + * Calculate the Inverse mirror/rotation transform. + * Useful to calculate coordinates relative to a component + * which must be for a non rotated, non mirrored item + * from the actual coordinate. + * @return The inverse transform. + */ + TRANSFORM InverseTransform( ) const; + + /** + * Calculate new angles according to the transform. + * + * @param aAngle1 = The first angle to transform + * @param aAngle2 = The second angle to transform + * @return True if the angles were swapped during the transform. + */ + bool MapAngles( int* aAngle1, int* aAngle2 ) const; +}; + + +#endif // _TRANSFORM_H_ diff --git a/eeschema/viewlib_frame.cpp b/eeschema/viewlib_frame.cpp new file mode 100644 index 00000000..ddcefa97 --- /dev/null +++ b/eeschema/viewlib_frame.cpp @@ -0,0 +1,595 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 + */ + +/** + * @file viewlib_frame.cpp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// Save previous component library viewer state. +wxString LIB_VIEW_FRAME::m_libraryName; +wxString LIB_VIEW_FRAME::m_entryName; + +int LIB_VIEW_FRAME::m_unit = 1; +int LIB_VIEW_FRAME::m_convert = 1; + + +BEGIN_EVENT_TABLE( LIB_VIEW_FRAME, EDA_DRAW_FRAME ) + // Window events + EVT_CLOSE( LIB_VIEW_FRAME::OnCloseWindow ) + EVT_SIZE( LIB_VIEW_FRAME::OnSize ) + EVT_ACTIVATE( LIB_VIEW_FRAME::OnActivate ) + + // Toolbar events + EVT_TOOL_RANGE( ID_LIBVIEW_NEXT, ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, + LIB_VIEW_FRAME::Process_Special_Functions ) + + EVT_TOOL( ID_LIBVIEW_CMP_EXPORT_TO_SCHEMATIC, LIB_VIEW_FRAME::ExportToSchematicLibraryPart ) + EVT_COMBOBOX( ID_LIBVIEW_SELECT_PART_NUMBER, LIB_VIEW_FRAME::Process_Special_Functions ) + + // listbox events + EVT_LISTBOX( ID_LIBVIEW_LIB_LIST, LIB_VIEW_FRAME::ClickOnLibList ) + EVT_LISTBOX( ID_LIBVIEW_CMP_LIST, LIB_VIEW_FRAME::ClickOnCmpList ) + EVT_LISTBOX_DCLICK( ID_LIBVIEW_CMP_LIST, LIB_VIEW_FRAME::DClickOnCmpList ) + + // Menu (and/or hotkey) events + EVT_MENU( wxID_HELP, EDA_DRAW_FRAME::GetKicadHelp ) + EVT_MENU( wxID_EXIT, LIB_VIEW_FRAME::CloseLibraryViewer ) + EVT_MENU( ID_SET_RELATIVE_OFFSET, LIB_VIEW_FRAME::OnSetRelativeOffset ) + +END_EVENT_TABLE() + + +/* Note: + * LIB_VIEW_FRAME can be build in "modal mode", or as a usual frame. + * In modal mode: + * a tool to export the selected symbol is shown in the toolbar + * the style is wxSTAY_ON_TOP on Windows and wxFRAME_FLOAT_ON_PARENT on unix + * reason: + * the parent is usually the kicad window manager (not easy to change) + * On windows, when the frame with stype wxFRAME_FLOAT_ON_PARENT is displayed + * its parent frame is brought to the foreground, on the top of the calling frame. + * and stays displayed when closing the LIB_VIEW_FRAME frame. + * this issue does not happen on unix. + * + * So we use wxSTAY_ON_TOP on Windows, and wxFRAME_FLOAT_ON_PARENT on unix + * to simulate a dialog called by ShowModal. + */ + +#define LIB_VIEW_FRAME_NAME wxT( "ViewlibFrame" ) + +LIB_VIEW_FRAME::LIB_VIEW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType, + PART_LIB* aLibrary ) : + SCH_BASE_FRAME( aKiway, aParent, aFrameType, _( "Library Browser" ), + wxDefaultPosition, wxDefaultSize, + aFrameType==FRAME_SCH_VIEWER_MODAL ? +#ifdef __WINDOWS__ + KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP : +#else + KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT : +#endif + KICAD_DEFAULT_DRAWFRAME_STYLE, + LIB_VIEW_FRAME_NAME ) +{ + wxASSERT( aFrameType == FRAME_SCH_VIEWER || aFrameType == FRAME_SCH_VIEWER_MODAL ); + + if( aFrameType == FRAME_SCH_VIEWER_MODAL ) + SetModal( true ); + + m_configFrameName = LIB_VIEW_FRAME_NAME; + + // Give an icon + wxIcon icon; + icon.CopyFromBitmap( KiBitmap( library_browse_xpm ) ); + SetIcon( icon ); + + m_hotkeysDescrList = g_Viewlib_Hokeys_Descr; + m_cmpList = NULL; + m_libList = NULL; + m_listPowerCmpOnly = false; + + SetScreen( new SCH_SCREEN( aKiway ) ); + GetScreen()->m_Center = true; // Axis origin centered on screen. + LoadSettings( config() ); + + SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); + + // Initialize grid id to the default value (50 mils): + m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000; + GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); + + // Menu bar is not mandatory: uncomment/comment the next line + // to add/remove the menubar + ReCreateMenuBar(); + ReCreateHToolbar(); + ReCreateVToolbar(); + + if( !aLibrary ) + { + // Creates the libraries window display + m_libList = new wxListBox( this, ID_LIBVIEW_LIB_LIST, + wxPoint( 0, 0 ), wxSize(m_libListWidth, -1), + 0, NULL, wxLB_HSCROLL ); + } + else + { + m_libraryName = aLibrary->GetName(); + m_entryName.Clear(); + m_unit = 1; + m_convert = 1; + m_libListWidth = 0; + } + + // Creates the component window display + m_cmpList = new wxListBox( this, ID_LIBVIEW_CMP_LIST, + wxPoint( 0, 0 ), wxSize(m_cmpListWidth, -1), + 0, NULL, wxLB_HSCROLL ); + + if( m_libList ) + ReCreateListLib(); + + DisplayLibInfos(); + + m_auimgr.SetManagedWindow( this ); + + EDA_PANEINFO horiz; + horiz.HorizontalToolbarPane(); + + EDA_PANEINFO vert; + vert.VerticalToolbarPane(); + + EDA_PANEINFO info; + info.InfoToolbarPane(); + + EDA_PANEINFO mesg; + mesg.MessageToolbarPane(); + + + // Manage main toolbal + m_auimgr.AddPane( m_mainToolBar, + wxAuiPaneInfo( horiz ).Name( wxT ("m_mainToolBar" ) ).Top().Row( 0 ) ); + + // Manage the left window (list of libraries) + if( m_libList ) + m_auimgr.AddPane( m_libList, wxAuiPaneInfo( info ).Name( wxT( "m_libList" ) ). + Left().Row( 0 ) ); + + // Manage the list of components) + m_auimgr.AddPane( m_cmpList, + wxAuiPaneInfo( info ).Name( wxT( "m_cmpList" ) ). + Left().Row( 1 ) ); + + // Manage the draw panel + m_auimgr.AddPane( m_canvas, + wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() ); + + // Manage the message panel + m_auimgr.AddPane( m_messagePanel, + wxAuiPaneInfo( mesg ).Name( wxT( "MsgPanel" ) ).Bottom().Layer(10) ); + + /* Now the minimum windows are fixed, set library list + * and component list of the previous values from last viewlib use + */ + if( m_libList ) + { + m_auimgr.GetPane( m_libList ).MinSize( wxSize( 80, -1) ); + m_auimgr.GetPane( m_libList ).BestSize( wxSize(m_libListWidth, -1) ); + } + + m_auimgr.GetPane( m_cmpList ).MinSize( wxSize( 80, -1) ); + m_auimgr.GetPane( m_cmpList ).BestSize(wxSize(m_cmpListWidth, -1) ); + + m_auimgr.Update(); + + // Now Drawpanel is sized, we can use BestZoom to show the component (if any) +#ifdef USE_WX_GRAPHICS_CONTEXT + GetScreen()->SetZoom( BestZoom() ); +#else + Zoom_Automatique( false ); +#endif + + if( !IsModal() ) // For modal mode, calling ShowModal() will show this frame + { + Raise(); + Show( true ); + } +} + + +LIB_VIEW_FRAME::~LIB_VIEW_FRAME() +{ +} + + +void LIB_VIEW_FRAME::OnCloseWindow( wxCloseEvent& Event ) +{ + if( !IsModal() ) + { + Destroy(); + } + else if( !IsDismissed() ) + { + // only dismiss modal frame if not already dismissed. + DismissModal( false ); + + // Modal frame will be destroyed by the calling function. + } +} + + +void LIB_VIEW_FRAME::OnSize( wxSizeEvent& SizeEv ) +{ + if( m_auimgr.GetManagedWindow() ) + m_auimgr.Update(); + + SizeEv.Skip(); +} + + +void LIB_VIEW_FRAME::OnSetRelativeOffset( wxCommandEvent& event ) +{ + GetScreen()->m_O_Curseur = GetCrossHairPosition(); + UpdateStatusBar(); +} + + +double LIB_VIEW_FRAME::BestZoom() +{ + /* Please, note: wxMSW before version 2.9 seems have + * problems with zoom values < 1 ( i.e. userscale > 1) and needs to be patched: + * edit file /src/msw/dc.cpp + * search for line static const int VIEWPORT_EXTENT = 1000; + * and replace by static const int VIEWPORT_EXTENT = 10000; + */ + + LIB_PART* part = NULL; + double bestzoom = 16.0; // default value for bestzoom + PART_LIB* lib = Prj().SchLibs()->FindLibrary( m_libraryName ); + + if( lib ) + part = lib->FindPart( m_entryName ); + + if( !part ) + { + SetScrollCenterPosition( wxPoint( 0, 0 ) ); + return bestzoom; + } + + wxSize size = m_canvas->GetClientSize(); + + EDA_RECT boundingBox = part->GetBoundingBox( m_unit, m_convert ); + + // Reserve a 10% margin around component bounding box. + double margin_scale_factor = 0.8; + double zx =(double) boundingBox.GetWidth() / + ( margin_scale_factor * (double)size.x ); + double zy = (double) boundingBox.GetHeight() / + ( margin_scale_factor * (double)size.y); + + // Calculates the best zoom + bestzoom = std::max( zx, zy ); + + // keep it >= minimal existing zoom (can happen for very small components + // like small power symbols + if( bestzoom < GetScreen()->m_ZoomList[0] ) + bestzoom = GetScreen()->m_ZoomList[0]; + + SetScrollCenterPosition( boundingBox.Centre() ); + + return bestzoom; +} + + +void LIB_VIEW_FRAME::ReCreateListLib() +{ + if( !m_libList ) + return; + + m_libList->Clear(); + + wxArrayString libs = Prj().SchLibs()->GetLibraryNames(); + + // Remove not allowed libs from main list, if the allowed lib list is not empty + if( m_allowedLibs.GetCount() ) + { + for( unsigned ii = 0; ii < libs.GetCount(); ) + { + if( m_allowedLibs.Index( libs[ii] ) == wxNOT_FOUND ) + libs.RemoveAt( ii ); + else + ii++; + } + } + + // Remove libs which have no power components, if this filter is activated + if( m_listPowerCmpOnly ) + { + for( unsigned ii = 0; ii < libs.GetCount(); ) + { + PART_LIB* lib = Prj().SchLibs()->FindLibrary( libs[ii] ); + + if( lib && !lib->HasPowerParts() ) + libs.RemoveAt( ii ); + else + ii++; + } + } + + m_libList->Append( libs ); + + // Search for a previous selection: + int index = m_libList->FindString( m_libraryName ); + + if( index != wxNOT_FOUND ) + { + m_libList->SetSelection( index, true ); + } + else + { + // If not found, clear current library selection because it can be + // deleted after a config change. + m_libraryName = wxEmptyString; + m_entryName = wxEmptyString; + m_unit = 1; + m_convert = 1; + } + + ReCreateListCmp(); + ReCreateHToolbar(); + DisplayLibInfos(); + m_canvas->Refresh(); +} + + +void LIB_VIEW_FRAME::ReCreateListCmp() +{ + if( m_cmpList == NULL ) + return; + + m_cmpList->Clear(); + + PART_LIB* lib = Prj().SchLibs()->FindLibrary( m_libraryName ); + + if( !lib ) + { + m_libraryName = wxEmptyString; + m_entryName = wxEmptyString; + m_convert = 1; + m_unit = 1; + return; + } + + wxArrayString nameList; + + if( m_listPowerCmpOnly ) + lib->GetEntryTypePowerNames( nameList ); + else + lib->GetEntryNames( nameList ); + + m_cmpList->Append( nameList ); + + int index = m_cmpList->FindString( m_entryName ); + + if( index == wxNOT_FOUND ) + { + m_entryName = wxEmptyString; + m_convert = 1; + m_unit = 1; + } + else + { + m_cmpList->SetSelection( index, true ); + } +} + + +void LIB_VIEW_FRAME::ClickOnLibList( wxCommandEvent& event ) +{ + int ii = m_libList->GetSelection(); + + if( ii < 0 ) + return; + + SetSelectedLibrary( m_libList->GetString( ii ) ); +} + + +void LIB_VIEW_FRAME::SetSelectedLibrary( const wxString& aLibraryName ) +{ + if( m_libraryName == aLibraryName ) + return; + + m_libraryName = aLibraryName; + ReCreateListCmp(); + m_canvas->Refresh(); + DisplayLibInfos(); + ReCreateHToolbar(); + + // Ensure the corresponding line in m_libList is selected + // (which is not necessary the case if SetSelectedLibrary is called + // by an other caller than ClickOnLibList. + m_libList->SetStringSelection( m_libraryName, true ); +} + + +void LIB_VIEW_FRAME::ClickOnCmpList( wxCommandEvent& event ) +{ + int ii = m_cmpList->GetSelection(); + + if( ii < 0 ) + return; + + SetSelectedComponent( m_cmpList->GetString( ii ) ); +} + + +void LIB_VIEW_FRAME::SetSelectedComponent( const wxString& aComponentName ) +{ + if( m_entryName.CmpNoCase( aComponentName ) != 0 ) + { + m_entryName = aComponentName; + + // Ensure the corresponding line in m_cmpList is selected + // (which is not necessarily the case if SetSelectedComponent is called + // by another caller than ClickOnCmpList. + m_cmpList->SetStringSelection( aComponentName, true ); + DisplayLibInfos(); + m_unit = 1; + m_convert = 1; + Zoom_Automatique( false ); + ReCreateHToolbar(); + m_canvas->Refresh(); + } +} + + +void LIB_VIEW_FRAME::DClickOnCmpList( wxCommandEvent& event ) +{ + if( IsModal() ) + { + ExportToSchematicLibraryPart( event ); + + // The schematic editor might not be the parent of the library viewer. + // It could be a python window. + SCH_EDIT_FRAME* schframe = dynamic_cast( GetParent() ); + + if( schframe ) + { + // Prevent the double click from being as a single click in the parent + // window which would cause the part to be parked rather than staying + // in drag mode. + schframe->SkipNextLeftButtonReleaseEvent(); + } + } +} + + +void LIB_VIEW_FRAME::ExportToSchematicLibraryPart( wxCommandEvent& event ) +{ + int ii = m_cmpList->GetSelection(); + + if( ii >= 0 ) + { + wxString part_name = m_cmpList->GetString( ii ); + + // a selection was made, pass true + DismissModal( true, part_name ); + } + else + { + // no selection was made, pass false + DismissModal( false ); + } + + Close( true ); +} + + +#define LIBLIST_WIDTH_KEY wxT( "ViewLiblistWidth" ) +#define CMPLIST_WIDTH_KEY wxT( "ViewCmplistWidth" ) + +// Currently, the library viewer has no dialog to change the background color +// of the draw canvas. Therefore the background color is here just +// in case of this option is added to some library viewer config dialog +#define LIBVIEW_BGCOLOR wxT( "LibviewBgColor" ) + + +void LIB_VIEW_FRAME::LoadSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::LoadSettings( aCfg ); + + SetGridColor( GetLayerColor( LAYER_GRID ) ); + SetDrawBgColor( GetLayerColor( LAYER_BACKGROUND ) ); + + aCfg->Read( LIBLIST_WIDTH_KEY, &m_libListWidth, 150 ); + aCfg->Read( CMPLIST_WIDTH_KEY, &m_cmpListWidth, 150 ); + + // Set parameters to a reasonable value. + if( m_libListWidth > m_FrameSize.x/2 ) + m_libListWidth = m_FrameSize.x/2; + + if( m_cmpListWidth > m_FrameSize.x/2 ) + m_cmpListWidth = m_FrameSize.x/2; +} + + +void LIB_VIEW_FRAME::SaveSettings( wxConfigBase* aCfg ) +{ + EDA_DRAW_FRAME::SaveSettings( aCfg ); + + if( m_libListWidth && m_libList ) + { + m_libListWidth = m_libList->GetSize().x; + aCfg->Write( LIBLIST_WIDTH_KEY, m_libListWidth ); + } + + m_cmpListWidth = m_cmpList->GetSize().x; + aCfg->Write( CMPLIST_WIDTH_KEY, m_cmpListWidth ); +} + + +void LIB_VIEW_FRAME::OnActivate( wxActivateEvent& event ) +{ + EDA_DRAW_FRAME::OnActivate( event ); + + if( m_libList ) + ReCreateListLib(); + + DisplayLibInfos(); +} + + +void LIB_VIEW_FRAME::CloseLibraryViewer( wxCommandEvent& event ) +{ + Close(); +} + +void LIB_VIEW_FRAME::SetFilter( const SCHLIB_FILTER* aFilter ) +{ + m_listPowerCmpOnly = false; + m_allowedLibs.Clear(); + + if( aFilter ) + { + m_allowedLibs = aFilter->GetAllowedLibList(); + m_listPowerCmpOnly = aFilter->GetFilterPowerParts(); + } + + ReCreateListLib(); +} diff --git a/eeschema/viewlib_frame.h b/eeschema/viewlib_frame.h new file mode 100644 index 00000000..ab7ecb21 --- /dev/null +++ b/eeschema/viewlib_frame.h @@ -0,0 +1,188 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2008-2014 Wayne Stambaugh + * Copyright (C) 2004-2014 KiCad Developers, see change_log.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 + */ + +/** + * @file viewlib_frame.h + */ + +#ifndef LIBVIEWFRM_H_ +#define LIBVIEWFRM_H_ + + +#include + +#include +#include + +class wxListBox; +class PART_LIB; +class SCHLIB_FILTER; + + +/** + * Component library viewer main window. + */ +class LIB_VIEW_FRAME : public SCH_BASE_FRAME +{ +public: + + /** + * Constructor + * @param aKiway + * @param aParent = the parent frame + * @param aFrameType must be given either FRAME_SCH_LIB_VIEWER or + * FRAME_SCH_LIB_VIEWER_MODAL + * @param aLibrary = the library to open when starting (default = NULL) + */ + LIB_VIEW_FRAME( KIWAY* aKiway, wxWindow* aParent, + FRAME_T aFrameType, PART_LIB* aLibrary = NULL ); + + ~LIB_VIEW_FRAME(); + + void OnSize( wxSizeEvent& event ); + + /** + * Function ReCreateListLib + * + * Creates or recreates the list of current loaded libraries. + * This list is sorted, with the library cache always at end of the list + */ + void ReCreateListLib(); + + void ReCreateListCmp(); + void Process_Special_Functions( wxCommandEvent& event ); + void DisplayLibInfos(); + void RedrawActiveWindow( wxDC* DC, bool EraseBg ); + void OnCloseWindow( wxCloseEvent& Event ); + void CloseLibraryViewer( wxCommandEvent& event ); + void ReCreateHToolbar(); + void ReCreateVToolbar(); + void ReCreateMenuBar(); + + void OnLeftClick( wxDC* DC, const wxPoint& MousePos ); + double BestZoom(); + void ClickOnLibList( wxCommandEvent& event ); + void ClickOnCmpList( wxCommandEvent& event ); + void OnSetRelativeOffset( wxCommandEvent& event ); + + bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); + + ///> @copydoc EDA_DRAW_FRAME::GetHotKeyDescription() + EDA_HOTKEY* GetHotKeyDescription( int aCommand ) const; + + /** + * Function OnHotKey + * handle hot key events. + * + */ + bool OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem = NULL ); + + void LoadSettings( wxConfigBase* aCfg ); + void SaveSettings( wxConfigBase* aCfg ); + + /** + * set a filter to display only libraries and/or components + * which match the filter + * + * @param aFilter is a filter to pass the allowed library name list + * and/or some other filter + * see SCH_BASE_FRAME::SelectComponentFromLibrary() for details. + * if aFilter == NULL, remove all filtering + */ + void SetFilter( const SCHLIB_FILTER* aFilter ); + + /** + * Set the selected library in the library window. + * + * @param aLibName name of the library to be selected. + */ + void SetSelectedLibrary( const wxString& aLibName ); + + /** + * Set the selected component. + * + * @param aComponentName : the name of the component to be selected. + */ + void SetSelectedComponent( const wxString& aComponentName ); + + // Accessors: + void SetUnit( int aUnit ) { m_unit = aUnit; } + int GetUnit( void ) { return m_unit; } + + void SetConvert( int aConvert ) { m_convert = aConvert; } + int GetConvert( void ) { return m_convert; } + +private: + /** + * Function OnActivate + * is called when the frame frame is activate to reload the libraries and component lists + * that can be changed by the schematic editor or the library editor. + */ + virtual void OnActivate( wxActivateEvent& event ); + + void SelectCurrentLibrary(); + void SelectAndViewLibraryPart( int option ); + + /** + * Function ExportToSchematicLibraryPart + * exports the current component to schematic and close the library browser. + */ + void ExportToSchematicLibraryPart( wxCommandEvent& event ); + void ViewOneLibraryContent( PART_LIB* Lib, int Flag ); + bool OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ); + void DClickOnCmpList( wxCommandEvent& event ); + +// Private members: + wxComboBox* m_selpartBox; + + // List of libraries (for selection ) + wxListBox* m_libList; // The list of libs + int m_libListWidth; // Last width of the window + + // List of components in the selected library + wxListBox* m_cmpList; // The list of components + int m_cmpListWidth; // Last width of the window + + // Filters to build list of libs/list of parts + bool m_listPowerCmpOnly; + wxArrayString m_allowedLibs; + + // TODO(hzeller): looks like these members were chosen to be static to survive different + // instances of this browser and communicate it to the next instance. This looks like an + // ugly hack, and should be solved differently. + static wxString m_libraryName; + + static wxString m_entryName; + + static int m_unit; + static int m_convert; + + DECLARE_EVENT_TABLE() +}; + +#endif // LIBVIEWFRM_H_ diff --git a/eeschema/viewlibs.cpp b/eeschema/viewlibs.cpp new file mode 100644 index 00000000..c71ea9d9 --- /dev/null +++ b/eeschema/viewlibs.cpp @@ -0,0 +1,310 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 KiCad Developers, see CHANGELOG.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 + */ + +/** + * @file viewlibs.cpp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define NEXT_PART 1 +#define NEW_PART 0 +#define PREVIOUS_PART -1 + + +void LIB_VIEW_FRAME::Process_Special_Functions( wxCommandEvent& event ) +{ + wxString msg; + LIB_ALIAS* entry; + int ii, id = event.GetId(); + + switch( id ) + { + case ID_LIBVIEW_SELECT_LIB: + SelectCurrentLibrary(); + break; + + case ID_LIBVIEW_SELECT_PART: + SelectAndViewLibraryPart( NEW_PART ); + break; + + case ID_LIBVIEW_NEXT: + SelectAndViewLibraryPart( NEXT_PART ); + break; + + case ID_LIBVIEW_PREVIOUS: + SelectAndViewLibraryPart( PREVIOUS_PART ); + break; + + case ID_LIBVIEW_VIEWDOC: + entry = Prj().SchLibs()->FindLibraryEntry( m_entryName, m_libraryName ); + + if( entry && !entry->GetDocFileName().IsEmpty() ) + { + SEARCH_STACK* lib_search = Prj().SchSearchS(); + + GetAssociatedDocument( this, entry->GetDocFileName(), lib_search ); + } + break; + + case ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT: + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, true ); + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, false ); + m_convert = 1; + m_canvas->Refresh(); + break; + + case ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT: + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT, false ); + m_mainToolBar->ToggleTool( ID_LIBVIEW_DE_MORGAN_CONVERT_BUTT, true ); + m_convert = 2; + m_canvas->Refresh(); + break; + + case ID_LIBVIEW_SELECT_PART_NUMBER: + ii = m_selpartBox->GetCurrentSelection(); + if( ii < 0 ) + return; + m_unit = ii + 1; + m_canvas->Refresh(); + break; + + default: + msg << wxT( "LIB_VIEW_FRAME::Process_Special_Functions error: id = " ) << id; + DisplayError( this, msg ); + break; + } +} + + +void LIB_VIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) +{ +} + + +bool LIB_VIEW_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ) +{ + return true; +} + + +void LIB_VIEW_FRAME::DisplayLibInfos() +{ + PART_LIBS* libs = Prj().SchLibs(); + + if( libs ) + { + PART_LIB* lib = libs->FindLibrary( m_libraryName ); + + wxString msg = _( "Library Browser" ); + + msg += wxT( " [" ); + + if( lib ) + msg += lib->GetFullFileName(); + else + msg += _( "no library selected" ); + + msg += wxT( "]" ); + + SetTitle( msg ); + } +} + + +void LIB_VIEW_FRAME::SelectCurrentLibrary() +{ + PART_LIB* Lib; + + Lib = SelectLibraryFromList(); + + if( Lib ) + { + m_entryName.Empty(); + m_libraryName = Lib->GetName(); + DisplayLibInfos(); + + if( m_libList ) + { + ReCreateListCmp(); + m_canvas->Refresh(); + DisplayLibInfos(); + ReCreateHToolbar(); + int id = m_libList->FindString( m_libraryName.GetData() ); + + if( id >= 0 ) + m_libList->SetSelection( id ); + } + } +} + + +void LIB_VIEW_FRAME::SelectAndViewLibraryPart( int option ) +{ + if( m_libraryName.IsEmpty() ) + SelectCurrentLibrary(); + + if( m_libraryName.IsEmpty() ) + return; + + if( PART_LIBS* libs = Prj().SchLibs() ) + { + if( PART_LIB* lib = libs->FindLibrary( m_libraryName ) ) + { + if( m_entryName.IsEmpty() || option == NEW_PART ) + { + ViewOneLibraryContent( lib, NEW_PART ); + return; + } + + if( lib->FindEntry( m_entryName ) ) + { + if( option == NEXT_PART ) + ViewOneLibraryContent( lib, NEXT_PART ); + + if( option == PREVIOUS_PART ) + ViewOneLibraryContent( lib, PREVIOUS_PART ); + } + } + } +} + + +void LIB_VIEW_FRAME::ViewOneLibraryContent( PART_LIB* Lib, int Flag ) +{ + int NumOfParts = 0; + + if( Lib ) + NumOfParts = Lib->GetCount(); + + if( NumOfParts == 0 ) + { + DisplayError( this, wxT( "No library or library is empty!" ) ); + return; + } + + LIB_ALIAS* entry; + wxString CmpName; + + if( Flag == NEW_PART ) + DisplayListComponentsInLib( Lib, CmpName, m_entryName ); + + if( Flag == NEXT_PART ) + { + entry = Lib->GetNextEntry( m_entryName ); + + if( entry ) + CmpName = entry->GetName(); + } + + if( Flag == PREVIOUS_PART ) + { + entry = Lib->GetPreviousEntry( m_entryName ); + + if( entry ) + CmpName = entry->GetName(); + } + + m_unit = 1; + m_convert = 1; + + entry = Lib->FindEntry( CmpName ); + m_entryName = CmpName; + DisplayLibInfos(); + Zoom_Automatique( false ); + m_canvas->Refresh( ); + + if( m_cmpList ) + { + int id = m_cmpList->FindString( m_entryName.GetData() ); + if( id >= 0 ) + m_cmpList->SetSelection( id ); + } + + ReCreateHToolbar(); +} + + +void LIB_VIEW_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg ) +{ + LIB_ALIAS* entry = Prj().SchLibs()->FindLibraryEntry( m_entryName, m_libraryName ); + + if( !entry ) + return; + + LIB_PART* part = entry->GetPart(); + + if( !part ) + return; + + wxString msg; + wxString tmp; + + m_canvas->DrawBackGround( DC ); + + if( !entry->IsRoot() ) + { + // Temporarily change the name field text to reflect the alias name. + msg = entry->GetName(); + tmp = part->GetName(); + + part->SetName( msg ); + + if( m_unit < 1 ) + m_unit = 1; + + if( m_convert < 1 ) + m_convert = 1; + } + else + msg = _( "None" ); + + part->Draw( m_canvas, DC, wxPoint( 0, 0 ), m_unit, m_convert, GR_DEFAULT_DRAWMODE ); + + // Redraw the cursor + m_canvas->DrawCrossHair( DC ); + + if( !tmp.IsEmpty() ) + part->SetName( tmp ); + + ClearMsgPanel(); + AppendMsgPanel( _( "Part" ), part->GetName(), BLUE, 6 ); + AppendMsgPanel( _( "Alias" ), msg, RED, 6 ); + AppendMsgPanel( _( "Description" ), entry->GetDescription(), CYAN, 6 ); + AppendMsgPanel( _( "Key words" ), entry->GetKeyWords(), DARKDARKGRAY ); +} -- cgit