CadToolMatrix.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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. include("scripts/Widgets/Widgets.js");
  20. /**
  21. * Represents a panel in the tool matrix. Panels are embedded as child items under
  22. * the root item of the appropriate category in the tool matrix tree.
  23. */
  24. function RCadToolMatrixTreePanel(parent, objectName) {
  25. QWidget.call(this, parent);
  26. this.objectName = objectName;
  27. this.autoFillBackground = true;
  28. var layout = new RFlowLayout(1,1,1);
  29. var iconSize = RSettings.getIntValue("CadToolMatrix/IconSize", 24);
  30. layout.setIconSize(new QSize(iconSize, iconSize));
  31. this.setLayout(layout);
  32. //var pal = new QPalette();
  33. //var color = pal.color(QPalette.Active, QPalette.Window);
  34. //var colorName = color.name();
  35. //var colorLightName = color.lighter(105).name();
  36. if (!RSettings.hasCustomStyleSheet()) {
  37. this.styleSheet =
  38. //"QWidget#" + objectName + " { background: qlineargradient( x1:0 y1:0, x2:1 y2:0, stop:0 " + colorName + ", stop:1 " + colorLightName + "); }"
  39. "QToolButton {"
  40. + " border-style: none;"
  41. + "}"
  42. + RCadToolMatrixTreePanel.getCheckedStyle()
  43. + RCadToolMatrixTreePanel.getPressedStyle();
  44. }
  45. }
  46. RCadToolMatrixTreePanel.prototype = new QWidget();
  47. RCadToolMatrixTreePanel.getCheckedStyle = function() {
  48. return "QToolButton:checked {"
  49. + " border-radius: 4px; "
  50. + " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #b7b7b7, stop: 0.8 #cfcfcf, stop: 1 #d1d1d1);"
  51. + "}";
  52. };
  53. RCadToolMatrixTreePanel.getPressedStyle = function() {
  54. return "QToolButton:pressed {"
  55. + " border-radius: 4px; "
  56. + " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #a4a4a4, stop: 0.8 #b3b3b3, stop: 1 #b5b5b5);"
  57. + "}";
  58. };
  59. /**
  60. * Inserts actions added to the panel into the flow layout of the panel.
  61. */
  62. RCadToolMatrixTreePanel.prototype.actionEvent = function(event) {
  63. var action = event.action();
  64. var layout = this.layout();
  65. var index;
  66. switch (event.type()) {
  67. case QEvent.ActionAdded:
  68. index = layout.count();
  69. if (event.before()) {
  70. if (RSettings.getQtVersion()>0x060000) {
  71. index = layout.indexOf(event.before());
  72. }
  73. else {
  74. index = layout.indexOf(event.before().getQAction());
  75. }
  76. }
  77. layout.insertAction(index, action);
  78. break;
  79. case QEvent.ActionChanged:
  80. layout.invalidate();
  81. break;
  82. case QEvent.ActionRemoved: {
  83. index = layout.indexOf(action);
  84. if (index !== -1) {
  85. var li = layout.takeAt(index);
  86. if (!isNull(li)) {
  87. var w = li.widget();
  88. if (!isNull(w)) {
  89. if (isFunction(w.destroy)) {
  90. destr(w);
  91. }
  92. }
  93. li.invalidate();
  94. }
  95. }
  96. break;
  97. }
  98. default:
  99. break;
  100. }
  101. };
  102. /**
  103. * CAD tool matrix tree widget.
  104. */
  105. function RCadToolMatrixTree(parent) {
  106. RTreeWidget.call(this, parent);
  107. //var buttonSize = RSettings.getIntValue("CadToolMatrix/IconSize", 32) * 1.25;
  108. this.header().hide();
  109. this.indentation = 0;
  110. this.rootIsDecorated = false;
  111. this.columnCount = 1;
  112. this.setAttribute(Qt.WA_MacShowFocusRect, false);
  113. this.selectionMode = QAbstractItemView.NoSelection;
  114. this.verticalScrollMode = QAbstractItemView.ScrollPerPixel;
  115. if (RSettings.getQtVersion()>0x050000) {
  116. this.header().setSectionResizeMode(0, QHeaderView.Stretch);
  117. }
  118. else {
  119. this.header().setResizeMode(0, QHeaderView.Stretch);
  120. }
  121. this.setItemDelegate(new RToolMatrixItemDelegate(this, this));
  122. //this.itemPressed.connect(this, "handleItemPress");
  123. this.itemPressed.connect(this, RCadToolMatrixTree.prototype.handleItemPress);
  124. this.minimumWidth = 120;
  125. if (RSettings.getQtVersion()>0x060000) {
  126. this.setSizeIncrement(new QSize(32,0));
  127. }
  128. else {
  129. this.sizeIncrement = new QSize(32,0);
  130. }
  131. var p = this.palette;
  132. p.setColor(QPalette.Base, new QColor("#dddddd"));
  133. this.palette = p;
  134. this.listViewMode = false;
  135. this.panStartValue = undefined;
  136. this.panStartY = undefined;
  137. }
  138. RCadToolMatrixTree.prototype = new RTreeWidget();
  139. RCadToolMatrixTree.prototype.resizeEvent = function(event) {
  140. RTreeWidget.prototype.resizeEvent.call(this, event);
  141. this.updatePanelSizes();
  142. };
  143. RCadToolMatrixTree.prototype.updatePanelSizes = function() {
  144. var embeddedWidgets = RCadToolMatrixTree.getItemsAndEmbeddedWidgets(this);
  145. for (var i=0; i<embeddedWidgets.length; i++) {
  146. var item = embeddedWidgets[i][0];
  147. var subItem = embeddedWidgets[i][1];
  148. var embeddedWidget = embeddedWidgets[i][2];
  149. var width = this.header().width;
  150. embeddedWidget.setFixedWidth(width);
  151. var layout = embeddedWidget.layout();
  152. var height = layout.heightForWidth(width);
  153. embeddedWidget.setFixedHeight(height);
  154. subItem.setSizeHint(0, new QSize(width, height));
  155. }
  156. //this.updateGeometries();
  157. };
  158. /**
  159. * Expand / collapse with single click.
  160. */
  161. RCadToolMatrixTree.prototype.handleItemPress = function(item) {
  162. if (isNull(item)) {
  163. return;
  164. }
  165. if (isFunction(QApplication.mouseButtons)) {
  166. // Qt 4:
  167. if (QApplication.mouseButtons().valueOf() !== Qt.LeftButton.valueOf()) {
  168. return;
  169. }
  170. }
  171. else {
  172. // Qt 5:
  173. if (QGuiApplication.mouseButtons().valueOf() !== Qt.LeftButton.valueOf()) {
  174. return;
  175. }
  176. }
  177. if (isNull(item.parent())) {
  178. item.setExpanded(!item.isExpanded());
  179. }
  180. // set focus to mdiChild
  181. var appWin = RMainWindowQt.getMainWindow();
  182. if (!isNull(appWin)) {
  183. var w = appWin.getMdiChild();
  184. if (!isNull(w)) {
  185. w.setFocus();
  186. }
  187. }
  188. };
  189. RCadToolMatrixTree.prototype.mousePressEvent = function(event) {
  190. if (event.button().valueOf() !== Qt.MidButton.valueOf()) {
  191. RTreeWidget.prototype.mousePressEvent.call(this, event);
  192. return;
  193. }
  194. // start panning:
  195. var sb = this.verticalScrollBar();
  196. this.panStartValue = sb.value;
  197. if (RSettings.getQtVersion()>=0x060000) {
  198. this.panStartY = event.position().y();
  199. }
  200. else {
  201. this.panStartY = event.y();
  202. }
  203. this.mouseTracking = true;
  204. };
  205. RCadToolMatrixTree.prototype.mouseReleaseEvent = function(event) {
  206. if (event.button().valueOf() !== Qt.MidButton.valueOf()) {
  207. RTreeWidget.prototype.mouseReleaseEvent.call(this, event);
  208. return;
  209. }
  210. // stop panning:
  211. this.panStartValue = undefined;
  212. this.panStartY = undefined;
  213. this.mouseTracking = false;
  214. };
  215. RCadToolMatrixTree.prototype.mouseMoveEvent = function(event) {
  216. if (isNull(this.panStartValue) || isNull(this.panStartY)) {
  217. return;
  218. }
  219. var sb = this.verticalScrollBar();
  220. if (RSettings.getQtVersion()>=0x060000) {
  221. sb.value = this.panStartValue + (this.panStartY - event.position().y()) * 4;
  222. }
  223. else {
  224. sb.value = this.panStartValue + (this.panStartY - event.y()) * 4;
  225. }
  226. };
  227. RCadToolMatrixTree.getItemsAndEmbeddedWidgets = function(tree) {
  228. var ret = [];
  229. for (var i=0; i<tree.topLevelItemCount; i++) {
  230. var item = tree.topLevelItem(i);
  231. var subItem = item.child(0);
  232. if (isNull(subItem)) {
  233. continue;
  234. }
  235. var embeddedWidget = tree.itemWidget(subItem, 0);
  236. if (isNull(embeddedWidget)) {
  237. continue;
  238. }
  239. ret.push([item, subItem, embeddedWidget]);
  240. }
  241. return ret;
  242. };
  243. RCadToolMatrixTree.prototype.filter = function(text) {
  244. var re;
  245. // hide all tool buttons / categories which don't match the filter:
  246. try {
  247. re = new RegExp(text, "gi");
  248. }
  249. catch(e) {
  250. re = new RegExp("", "gi");
  251. }
  252. var embeddedWidgets = RCadToolMatrixTree.getItemsAndEmbeddedWidgets(this);
  253. for (var i=0; i<embeddedWidgets.length; i++) {
  254. var item = embeddedWidgets[i][0];
  255. var objectName = item.data(0, Qt.UserRole+1);
  256. var settingsKey = objectName.replace("MatrixPanel", "");
  257. var embeddedWidget = embeddedWidgets[i][2];
  258. //qDebug("settingsKey:", settingsKey);
  259. var children = embeddedWidget.children();
  260. var found = false;
  261. for (var k=0; k<children.length; k++) {
  262. var child = children[k];
  263. if (!isOfType(child, RToolButton) && !isOfType(child, QToolButton)) {
  264. continue;
  265. }
  266. if (!isFunction(child.defaultAction)) {
  267. continue;
  268. }
  269. var action = child.defaultAction();
  270. if (isNull(action)) {
  271. continue;
  272. }
  273. if (text.length===0) {
  274. // no filter:
  275. found = true;
  276. //child.styleSheet = "QToolButton { border-style: none; }";
  277. child.visible = true;
  278. }
  279. else {
  280. var actionText = action.text.replace("&", "");
  281. var commands = action.getCommands();
  282. var match = re.test(actionText) || re.test(item.text(0));
  283. match = match || commands.contains(actionText, function(t) { return re.test(t); });
  284. if (match) {
  285. // filter match:
  286. child.visible = true;
  287. found = true;
  288. // child.styleSheet = "QToolButton { border-style: none; border-radius: 4px; background-color: white; }"
  289. // + RCadToolMatrixTreePanel.getCheckedStyle() + RCadToolMatrixTreePanel.getPressedStyle();
  290. }
  291. else {
  292. // filter does not match:
  293. child.visible = false;
  294. // child.styleSheet = "";
  295. }
  296. }
  297. }
  298. if (!found || RSettings.getBoolValue(settingsKey + "/VisibleInMatrixPanel", true)===false) {
  299. // hide category:
  300. item.setHidden(true);
  301. }
  302. else {
  303. item.setHidden(false);
  304. }
  305. }
  306. //this.updatePanelSizes();
  307. RCadToolMatrixTree.prototype.updatePanelSizes.call(this);
  308. };
  309. RCadToolMatrixTree.prototype.updateIconSize = function() {
  310. var iconSize = RSettings.getIntValue("CadToolMatrix/IconSize", 24);
  311. iconSize = new QSize(iconSize, iconSize);
  312. var embeddedWidgets = RCadToolMatrixTree.getItemsAndEmbeddedWidgets(this);
  313. for (var i=0; i<embeddedWidgets.length; i++) {
  314. var embeddedWidget = embeddedWidgets[i][2];
  315. var layout = embeddedWidget.layout();
  316. layout.setIconSize(iconSize);
  317. // var children = embeddedWidget.children();
  318. // var found = false;
  319. // for (var k=0; k<children.length; k++) {
  320. // var child = children[k];
  321. // if (!isOfType(child, QToolButton)) {
  322. // continue;
  323. // }
  324. // child.iconSize = iconSize;
  325. // }
  326. //layout.invalidate();
  327. //item.setExpanded(!item.isExpanded());
  328. //item.setExpanded(!item.isExpanded());
  329. // var width = this.header().width;
  330. // embeddedWidget.setFixedWidth(width);
  331. // var height = embeddedWidget.layout().heightForWidth(width);
  332. // embeddedWidget.setFixedHeight(height);
  333. // subItem.setSizeHint(0, new QSize(width, height));
  334. }
  335. //this.resize(this.size);
  336. //this.updatePanelSizes();
  337. };
  338. RCadToolMatrixTree.prototype.contextMenuEvent = function(event) {
  339. var menu = new QMenu(RMainWindowQt.getMainWindow());
  340. var self = this;
  341. var a;
  342. a = menu.addAction(qsTr("Expand all"));
  343. a.triggered.connect(function() {
  344. self.expandAll();
  345. });
  346. a = menu.addAction(qsTr("Collapse all"));
  347. a.triggered.connect(function() {
  348. self.collapseAll();
  349. });
  350. menu.addSeparator();
  351. a = menu.addAction(qsTr("List View"));
  352. a.triggered.connect(function() {
  353. self.setListViewMode(true);
  354. });
  355. a = menu.addAction(qsTr("Icon View"));
  356. a.triggered.connect(function() {
  357. self.setListViewMode(false);
  358. });
  359. menu.exec(QCursor.pos());
  360. };
  361. RCadToolMatrixTree.prototype.updateListViewMode = function() {
  362. var listViewMode = RSettings.getBoolValue("CadToolMatrix/ListViewMode", false);
  363. RCadToolMatrixTree.prototype.setListViewMode.call(this, listViewMode);
  364. };
  365. RCadToolMatrixTree.prototype.setListViewMode = function(enable) {
  366. if (isFunction(this.setProperty)) {
  367. this.setProperty("listViewMode", enable);
  368. }
  369. var embeddedWidgets = RCadToolMatrixTree.getItemsAndEmbeddedWidgets(this);
  370. for (var i=0; i<embeddedWidgets.length; i++) {
  371. var embeddedWidget = embeddedWidgets[i][2];
  372. var layout = embeddedWidget.layout();
  373. layout.setListViewMode(enable);
  374. }
  375. RCadToolMatrixTree.prototype.updatePanelSizes.call(this);
  376. };
  377. function CadToolMatrix(guiAction) {
  378. Widgets.call(this, guiAction);
  379. }
  380. CadToolMatrix.prototype = new Widgets();
  381. CadToolMatrix.includeBasePath = includeBasePath;
  382. CadToolMatrix.getPreferencesCategory = function() {
  383. return [qsTr("Widgets"), qsTr("Tool Matrix")];
  384. };
  385. CadToolMatrix.applyPreferences = function(doc) {
  386. if (!isNull(doc)) {
  387. // document settings: nothing to do
  388. return;
  389. }
  390. var appWin = EAction.getMainWindow();
  391. if (isNull(appWin)) {
  392. return;
  393. }
  394. var cadToolMatrix = appWin.findChild("ToolMatrix");
  395. RCadToolMatrixTree.prototype.updateIconSize.call(cadToolMatrix);
  396. RCadToolMatrixTree.prototype.updateListViewMode.call(cadToolMatrix);
  397. var cadToolMatrixDock = appWin.findChild("ToolMatrixDock");
  398. RCadToolMatrixTree.prototype.filter.call(cadToolMatrix, cadToolMatrixDock.findChild("FilterEdit").text);
  399. //RCadToolMatrixTree.prototype.updatePanelSizes.call(cadToolMatrix);
  400. };
  401. /**
  402. * \return Newly created or existing instance of RCadToolMatrixTree.
  403. */
  404. CadToolMatrix.getToolMatrix = function() {
  405. var appWin = EAction.getMainWindow();
  406. var toolMatrix = appWin.findChild("ToolMatrix");
  407. if (isNull(toolMatrix)) {
  408. var formWidget = WidgetFactory.createWidget(CadToolMatrix.includeBasePath, "CadToolMatrix.ui");
  409. var layout = formWidget.findChild("VerticalLayout");
  410. // add tool matrix:
  411. toolMatrix = new RCadToolMatrixTree(appWin);
  412. toolMatrix.objectName = "ToolMatrix";
  413. if (RSettings.getQtVersion()>0x060000) {
  414. layout.addWidget(toolMatrix);
  415. }
  416. else {
  417. layout.addWidget(toolMatrix, 1, 0);
  418. }
  419. // init filter widget:
  420. var filterEdit = formWidget.findChild("FilterEdit");
  421. //filterEdit.textChanged.connect(toolMatrix, "filter");
  422. filterEdit.textChanged.connect(toolMatrix, toolMatrix.filter);
  423. var clearButton = formWidget.findChild("Clear");
  424. if (filterEdit.clearButtonEnabled===true) {
  425. clearButton.hide();
  426. }
  427. var dock = new RDockWidget(qsTr("Tool Matrix"), appWin);
  428. dock.objectName = "ToolMatrixDock";
  429. dock.setWidget(formWidget);
  430. appWin.addDockWidget(Qt.LeftDockWidgetArea, dock);
  431. dock.visible = false;
  432. }
  433. return toolMatrix;
  434. };
  435. /**
  436. * \return RCadToolMatrixTreePanel with RFlowLayout to which QActions can be added as part of a
  437. * tool panel in the tools matrix. The category in the tool matrix tree is added if
  438. * it is not yet present.
  439. */
  440. CadToolMatrix.getToolMatrixPanel = function(title, objectName, order) {
  441. var appWin = EAction.getMainWindow();
  442. if (isNull(appWin)) {
  443. return undefined;
  444. }
  445. var dw = appWin.findChild(objectName);
  446. if (!isNull(dw)) {
  447. return dw;
  448. }
  449. title = title.replace("&", "");
  450. //var settingsKey = objectName.replace("MatrixPanel", "");
  451. var tm = CadToolMatrix.getToolMatrix();
  452. // find existing root item:
  453. var flags = makeQtMatchFlags(Qt.MatchFixedString, Qt.MatchRecursive);
  454. var items = tm.findItems(title, flags);
  455. var item;
  456. if (items.length===0) {
  457. // add root item at desired position:
  458. item = new QTreeWidgetItem();
  459. item.setChildIndicatorPolicy(QTreeWidgetItem.ShowIndicator);
  460. item.setText(0, title);
  461. // item.setText(0, title + "_" + order);
  462. item.setData(0, Qt.UserRole, order);
  463. item.setData(0, Qt.UserRole+1, objectName);
  464. // if (RSettings.getBoolValue(settingsKey + "/VisibleInMatrixPanel", true)===false) {
  465. // //item.setHidden(true);
  466. // item.setData(0, Qt.UserRole+2, false);
  467. // }
  468. var found = false;
  469. for (var i=0; i<tm.topLevelItemCount; i++) {
  470. var topLevelItem = tm.topLevelItem(i);
  471. var o = topLevelItem.data(0, Qt.UserRole);
  472. if (o>order) {
  473. tm.insertTopLevelItem(i, item);
  474. found = true;
  475. break;
  476. }
  477. }
  478. if (!found) {
  479. tm.addTopLevelItem(item);
  480. }
  481. }
  482. else {
  483. item = items[0];
  484. }
  485. var subItem = new QTreeWidgetItem();
  486. dw = new RCadToolMatrixTreePanel(tm, objectName);
  487. item.addChild(subItem);
  488. tm.setItemWidget(subItem, 0, dw);
  489. tm.expandAll();
  490. return dw;
  491. };
  492. /**
  493. * Restore state of collapsed categories.
  494. */
  495. CadToolMatrix.postInit = function(basePath) {
  496. var appWin = EAction.getMainWindow();
  497. if (isNull(appWin)) {
  498. return undefined;
  499. }
  500. var toolMatrix = appWin.findChild("ToolMatrix");
  501. if (isNull(toolMatrix)) {
  502. return;
  503. }
  504. var listViewMode = RSettings.getBoolValue("CadToolMatrix/ListViewMode", false);
  505. RCadToolMatrixTree.prototype.setListViewMode.call(toolMatrix, listViewMode);
  506. var closedCategories = RSettings.getStringValue("CadToolMatrix/ClosedCategories", "");
  507. closedCategories = closedCategories.split(",");
  508. for (var i=0; i<toolMatrix.topLevelItemCount; i++) {
  509. var item = toolMatrix.topLevelItem(i);
  510. var id = item.data(0, Qt.UserRole+1);
  511. if (closedCategories.contains(id)) {
  512. item.setExpanded(false);
  513. }
  514. }
  515. RCadToolMatrixTree.prototype.filter.call(toolMatrix, "");
  516. };
  517. /**
  518. * Store state of collapsed categories.
  519. */
  520. CadToolMatrix.uninit = function() {
  521. var appWin = EAction.getMainWindow();
  522. if (isNull(appWin)) {
  523. return undefined;
  524. }
  525. var toolMatrix = appWin.findChild("ToolMatrix");
  526. if (isNull(toolMatrix)) {
  527. return;
  528. }
  529. // store expanded state:
  530. var closedCategories = [];
  531. for (var i=0; i<toolMatrix.topLevelItemCount; i++) {
  532. var item = toolMatrix.topLevelItem(i);
  533. if (!item.isExpanded()) {
  534. var id = item.data(0, Qt.UserRole+1);
  535. closedCategories.push(id);
  536. }
  537. }
  538. RSettings.setValue("CadToolMatrix/ClosedCategories", closedCategories.join(","));
  539. // TODO #qt6:
  540. if (RSettings.getQtVersion()<0x060000) {
  541. RSettings.setValue("CadToolMatrix/ListViewMode", toolMatrix.listViewMode);
  542. }
  543. };