Dimension.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /**
  2. * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
  3. *
  4. * This file is part of the QCAD project.
  5. *
  6. * QCAD is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * QCAD is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with QCAD.
  18. */
  19. /**
  20. * \defgroup ecma_draw_dimension Dimension Drawing Tools
  21. * \ingroup ecma_draw
  22. *
  23. * \brief This module contains ECMAScript implementations of various dimensioning tools.
  24. */
  25. include("scripts/Draw/Draw.js");
  26. /**
  27. * \class Dimension
  28. * \brief Base class for all dimensioning tools.
  29. * \ingroup ecma_draw_dimension
  30. */
  31. function Dimension(guiAction) {
  32. EAction.call(this, guiAction);
  33. this.data = undefined;
  34. }
  35. Dimension.prototype = new EAction();
  36. Dimension.includeBasePath = includeBasePath;
  37. Dimension.prototype.beginEvent = function() {
  38. EAction.prototype.beginEvent.call(this);
  39. if (!isNull(this.getGuiAction()) && this.getGuiAction().objectName==="DimensionToolsPanelAction") {
  40. EAction.showCadToolBarPanel("DimensionToolsPanel");
  41. this.terminate();
  42. }
  43. };
  44. /**
  45. * Reimplemented to reset all fields, unless we are resuming.
  46. */
  47. Dimension.prototype.initUiOptions = function(resume, optionsToolBar) {
  48. EAction.prototype.initUiOptions.call(this, resume, optionsToolBar);
  49. var prefixCombo = optionsToolBar.findChild("Prefix");
  50. if (!isNull(prefixCombo)) {
  51. prefixCombo.clear();
  52. prefixCombo.addItem("(" + qsTr("No prefix") + ")");
  53. prefixCombo.addItem("R (" + qsTr("Radius") + ")");
  54. prefixCombo.addItem("M (" + qsTr("Metric screw") + ")");
  55. prefixCombo.addItem("\u00F8 (" + qsTr("Diameter") + ")");
  56. prefixCombo.addItem("\u2312 (" + qsTr("Arc") + ")");
  57. prefixCombo.addItem("\u00B1 (" + qsTr("Plus/Minus") + ")");
  58. prefixCombo.addItem("\u2248 (" + qsTr("Almost equal to") + ")");
  59. prefixCombo.addItem("\u2243 (" + qsTr("Asymptotically equal to") + ")");
  60. prefixCombo.addItem("\u25FB (" + qsTr("Square") + ")");
  61. prefixCombo.addItem("\u0394 (" + qsTr("Delta") + ")");
  62. prefixCombo.currentIndex = 0;
  63. }
  64. var textLineEdit = optionsToolBar.findChild("Text");
  65. if (!isNull(textLineEdit)) {
  66. textLineEdit.text = "";
  67. WidgetFactory.initLineEdit(textLineEdit, true);
  68. }
  69. var upperToleranceLineEdit = optionsToolBar.findChild("UpperTolerance");
  70. if (!isNull(upperToleranceLineEdit)) {
  71. upperToleranceLineEdit.text = "";
  72. WidgetFactory.initLineEdit(upperToleranceLineEdit, true);
  73. }
  74. var lowerToleranceLineEdit = optionsToolBar.findChild("LowerTolerance");
  75. if (!isNull(lowerToleranceLineEdit)) {
  76. lowerToleranceLineEdit.text = "";
  77. WidgetFactory.initLineEdit(lowerToleranceLineEdit, true);
  78. }
  79. this.initScaleCombo();
  80. // not a layout block: hide auto checkbox:
  81. var doc = this.getDocument();
  82. if (!isNull(doc)) {
  83. var block = doc.queryCurrentBlock();
  84. if (!isNull(block) && block.hasLayout() && block.isModelSpace()) {
  85. var cbAutoAction = optionsToolBar.findChild("AutoScaleAction");
  86. if (!isNull(cbAutoAction)) {
  87. cbAutoAction.visible = false;
  88. var cbAuto = optionsToolBar.findChild("AutoScale");
  89. cbAuto.checked = false;
  90. if (!resume) {
  91. // don't (re-)initialize or save state of auto checkbox:
  92. cbAuto.setProperty("Loaded", true);
  93. cbAuto.setProperty("Saved", true);
  94. }
  95. var scaleCombo = optionsToolBar.findChild("Scale");
  96. scaleCombo.setEnabled(true);
  97. }
  98. }
  99. }
  100. // if we are resuming, restore previous values (automatic)
  101. // it not, keep them empty.
  102. if (!resume) {
  103. if (!isNull(prefixCombo)) {
  104. prefixCombo.setProperty("Loaded", true);
  105. }
  106. if (!isNull(textLineEdit)) {
  107. textLineEdit.setProperty("Loaded", true);
  108. }
  109. if (!isNull(upperToleranceLineEdit)) {
  110. upperToleranceLineEdit.setProperty("Loaded", true);
  111. }
  112. if (!isNull(lowerToleranceLineEdit)) {
  113. lowerToleranceLineEdit.setProperty("Loaded", true);
  114. }
  115. }
  116. };
  117. Dimension.prototype.showUiOptions = function(resume, restoreFromSettings) {
  118. EAction.prototype.showUiOptions.call(this, resume, restoreFromSettings);
  119. if (!resume) {
  120. var factor = this.getFactor();
  121. if (!RMath.fuzzyCompare(factor, 1) && RSettings.getBoolValue("DimensionScaleDialog/DontShowDialog", false)!==true) {
  122. // warning if scale is not 1:
  123. var appWin = RMainWindowQt.getMainWindow();
  124. var dialog = WidgetFactory.createDialog(Dimension.includeBasePath, "DimensionScaleDialog.ui", appWin);
  125. dialog.exec();
  126. WidgetFactory.saveState(dialog);
  127. destr(dialog);
  128. EAction.activateMainWindow();
  129. }
  130. }
  131. };
  132. Dimension.prototype.initScaleCombo = function() {
  133. var document = this.getDocument();
  134. if (isNull(document)) {
  135. return;
  136. }
  137. var optionsToolBar = EAction.getOptionsToolBar();
  138. var scaleCombo = optionsToolBar.findChild("Scale");
  139. if (isNull(scaleCombo)) {
  140. return;
  141. }
  142. scaleCombo.blockSignals(true);
  143. var prev = scaleCombo.currentText;
  144. scaleCombo.clear();
  145. scaleCombo.setScale(true, document.getUnit())
  146. // var scales = this.getScales();
  147. // for (var i=0; i<scales.length; ++i) {
  148. // scaleCombo.addItem(scales[i]);
  149. // }
  150. scaleCombo.setEditText(prev);
  151. scaleCombo.blockSignals(false);
  152. };
  153. Dimension.getMenu = function() {
  154. // var menu = EAction.getMenu(Dimension.getTitle(), "DimensionMenu");
  155. // menu.setProperty("scriptFile", Dimension.includeBasePath + "/Dimension.js");
  156. // return menu;
  157. };
  158. Dimension.getToolBar = function() {
  159. var tb = EAction.getToolBar(Dimension.getTitle(), "DimensionToolBar", Qt.TopToolBarArea, Draw.getContextMenuCategory());
  160. tb.visible = false;
  161. return tb;
  162. };
  163. Dimension.getCadToolBarPanel = function() {
  164. var mtb = Draw.getCadToolBarPanel();
  165. var actionName = "DimensionToolsPanelAction";
  166. if (!isNull(mtb) && mtb.findChild(actionName)==undefined) {
  167. var action = new RGuiAction(qsTr("Dimension Tools"), mtb);
  168. action.setScriptFile(Dimension.includeBasePath + "/Dimension.js");
  169. action.objectName = actionName;
  170. action.setRequiresDocument(true);
  171. action.setIcon(Dimension.includeBasePath + "/Dimension.svg");
  172. //action.setStatusTip(qsTr("Show dimension tools"));
  173. action.setDefaultShortcut(new QKeySequence("w,d"));
  174. action.setNoState();
  175. action.setDefaultCommands(["dimensionmenu"]);
  176. action.setGroupSortOrder(30);
  177. action.setSortOrder(200);
  178. action.setWidgetNames(["MainToolsPanel"]);
  179. }
  180. var tb = EAction.getCadToolBarPanel(
  181. Dimension.getTitle(),
  182. "DimensionToolsPanel",
  183. true
  184. );
  185. return tb;
  186. };
  187. Dimension.getToolMatrixPanel = function() {
  188. return EAction.getToolMatrixPanel(Dimension.getTitle(), "DimensionMatrixPanel", 2100);
  189. };
  190. Dimension.getTitle = function() {
  191. return qsTr("D&imension");
  192. };
  193. Dimension.prototype.getTitle = function() {
  194. return Dimension.getTitle();
  195. };
  196. Dimension.init = function() {
  197. Dimension.getMenu();
  198. Dimension.getToolBar();
  199. Dimension.getCadToolBarPanel();
  200. Dimension.getToolMatrixPanel();
  201. };
  202. /**
  203. * Called when the user changes the text in the options toolbar.
  204. */
  205. Dimension.prototype.slotTextChanged = function() {
  206. this.updateText();
  207. };
  208. /**
  209. * Called when the user changes the prefix in the options toolbar.
  210. */
  211. Dimension.prototype.slotPrefixChanged = function(prefix) {
  212. this.updateText();
  213. };
  214. /**
  215. * \internal
  216. * Updates the text label of the constructed dimension entity according
  217. * to the prefix and text entered by the user.
  218. */
  219. Dimension.prototype.updateText = function() {
  220. if (isNull(this.data)) {
  221. return;
  222. }
  223. var optionsToolBar = EAction.getOptionsToolBar();
  224. var prefixCombo = optionsToolBar.findChild("Prefix");
  225. var textLineEdit = optionsToolBar.findChild("Text");
  226. var text = textLineEdit.text;
  227. var prefix = "";
  228. if (!isNull(prefixCombo)) {
  229. prefix = prefixCombo.currentText.replace(/[ ]*\(.*\)/, "");
  230. }
  231. if (prefix.length>0 && text.length===0) {
  232. this.data.setText(prefix + "<>");
  233. }
  234. else {
  235. this.data.setText(prefix + text);
  236. }
  237. };
  238. /**
  239. * Called when the user changes the upper tolerance in the options toolbar.
  240. */
  241. Dimension.prototype.slotUpperToleranceChanged = function(text) {
  242. if (!isNull(this.data)) {
  243. this.data.setUpperTolerance(text);
  244. }
  245. };
  246. /**
  247. * Called when the user changes the lower tolerance in the options toolbar.
  248. */
  249. Dimension.prototype.slotLowerToleranceChanged = function(text) {
  250. if (!isNull(this.data)) {
  251. this.data.setLowerTolerance(text);
  252. }
  253. };
  254. Dimension.prototype.getScaleString = function() {
  255. var optionsToolBar = EAction.getOptionsToolBar();
  256. var scaleCombo = optionsToolBar.findChild("Scale");
  257. return scaleCombo.currentText;
  258. };
  259. Dimension.prototype.getFactor = function() {
  260. var scale = this.parseScale(this.getScaleString());
  261. if (!RMath.fuzzyCompare(scale, 0)) {
  262. return 1 / scale;
  263. }
  264. return 1;
  265. };
  266. /**
  267. * Parses the given scale string (e.g. "1:2") and returns the scale as number (e.g. 0.5).
  268. */
  269. Dimension.prototype.parseScale = function(scaleString) {
  270. return RMath.parseScale(scaleString);
  271. };
  272. /**
  273. * Automatically adjust the dimension scale based on the context of a viewport.
  274. */
  275. Dimension.prototype.autoAdjustScale = function(pos) {
  276. var optionsToolBar = EAction.getOptionsToolBar();
  277. var cbAuto = optionsToolBar.findChild("AutoScale");
  278. if (isNull(cbAuto) || !cbAuto.checked) {
  279. return;
  280. }
  281. var doc = this.getDocument();
  282. // are we in a layout block:
  283. var block = doc.queryCurrentBlock();
  284. if (isNull(block) || !block.hasLayout()) {
  285. return;
  286. }
  287. // get scale of underlying viewport:
  288. var scale = undefined;
  289. var viewportIds = doc.queryAllEntities(false, false, RS.EntityViewport);
  290. for (var i=0; i<viewportIds.length; i++) {
  291. var viewportId = viewportIds[i];
  292. var viewport = doc.queryEntityDirect(viewportId);
  293. var box = viewport.getBoundingBox();
  294. if (box.containsPoint(pos)) {
  295. scale = viewport.getScale();
  296. break;
  297. }
  298. }
  299. // no viewport under pos:
  300. if (isNull(scale)) {
  301. scale = 1.0;
  302. }
  303. // set scale of dimension according to viewport:
  304. var scaleCombo = optionsToolBar.findChild("Scale");
  305. if (isNull(scaleCombo)) {
  306. return;
  307. }
  308. scaleCombo.currentText = RUnit.doubleToStringDec(scale, 12);
  309. };