├── Resources
└── icons
│ ├── PieMenuQuickMenu.svg
│ ├── PieMenuRemove.svg
│ ├── PieMenuReset.svg
│ ├── PieMenuRemoveCommand.svg
│ ├── PieMenuAdd.svg
│ ├── PieMenuAddCommand.svg
│ ├── PieMenuUp.svg
│ ├── PieMenuDown.svg
│ ├── PieMenuClose.svg
│ ├── PieMenuCopy.svg
│ ├── PieMenuAddSeparator.svg
│ ├── PieMenuRename.svg
│ ├── PieMenuAddMenu.svg
│ ├── PieMenuEditMenu.svg
│ └── PieMenu_Logo.svg
├── README.md
├── package.xml
├── PieMenuLocator.py
├── License
└── lgpl-2.1.txt
└── InitGui.py
/Resources/icons/PieMenuQuickMenu.svg:
--------------------------------------------------------------------------------
1 |
2 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PieMenu
2 | PieMenu widget for FreeCAD
3 |
4 | 
5 |
6 | ### Installation
7 | Since FreeCAD v0.16+ PieMenu can be installed via the FreeCAD [Addon Manager](https://github.com/FreeCAD/FreeCAD-addons#1-builtin-addon-manager).
8 |
9 | #### Manual installation:
10 |
11 | Install path for FreeCAD modules depends on the operating system used.
12 |
13 | ##### Examples:
14 |
15 | Linux:
16 |
17 | `/home/user/.FreeCAD/Mod/PieMenu/InitGui.py`
18 |
19 | macOS:
20 |
21 | `/Users/user_name/Library/Preferences/FreeCAD/Mod/PieMenu/InitGui.py`
22 |
23 | Windows:
24 |
25 | `C:\Users\user_name\AppData\Roaming\FreeCAD\Mod\PieMenu\InitGui.py`
26 |
27 | ### Usage
28 | Press the Tab key on the keyboard to invoke PieMenu.
29 |
30 | ### Discussion
31 | FreeCAD forum thread: https://forum.freecadweb.org/viewtopic.php?f=34&t=72205
32 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuRemove.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuReset.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | PieMenu
4 | The PieMenu module is a tool to accelerate and simplify your workflow in usage of FreeCAD.
5 | 1.2.7
6 | 2023-3-25
7 | Michael Dingerkus
8 | LGPLv2.1
9 | https://github.com/mdkus/PieMenu
10 | https://github.com/mdkus/PieMenu/issues
11 |
12 | Resources/icons/PieMenu_Logo.svg
13 |
14 |
15 |
16 | PieMenu
17 | ./
18 | Resources/icons/PieMenu_Logo.svg
19 | pie
20 | menu
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuRemoveCommand.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/PieMenuLocator.py:
--------------------------------------------------------------------------------
1 | # Pie menu for FreeCAD
2 | # Copyright (C) 2019 triplus @ FreeCAD
3 | #
4 | #
5 | # This library is free software; you can redistribute it and/or
6 | # modify it under the terms of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation; either
8 | # version 2.1 of the License, or (at your option) any later version.
9 | #
10 | # This library is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public
16 | # License along with this library; if not, write to the Free Software
17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 |
19 | """Pie menu for FreeCAD - Locator."""
20 |
21 |
22 | import os
23 |
24 |
25 | def path():
26 | """Return module path location."""
27 | return os.path.dirname(__file__)
28 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuAdd.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuAddCommand.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuUp.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuDown.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuClose.svg:
--------------------------------------------------------------------------------
1 |
2 |
38 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuCopy.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuAddSeparator.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuRename.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuAddMenu.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenuEditMenu.svg:
--------------------------------------------------------------------------------
1 |
34 |
--------------------------------------------------------------------------------
/License/lgpl-2.1.txt:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 2.1, February 1999
3 |
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | [This is the first released version of the Lesser GPL. It also counts
10 | as the successor of the GNU Library Public License, version 2, hence
11 | the version number 2.1.]
12 |
13 | Preamble
14 |
15 | The licenses for most software are designed to take away your
16 | freedom to share and change it. By contrast, the GNU General Public
17 | Licenses are intended to guarantee your freedom to share and change
18 | free software--to make sure the software is free for all its users.
19 |
20 | This license, the Lesser General Public License, applies to some
21 | specially designated software packages--typically libraries--of the
22 | Free Software Foundation and other authors who decide to use it. You
23 | can use it too, but we suggest you first think carefully about whether
24 | this license or the ordinary General Public License is the better
25 | strategy to use in any particular case, based on the explanations below.
26 |
27 | When we speak of free software, we are referring to freedom of use,
28 | not price. Our General Public Licenses are designed to make sure that
29 | you have the freedom to distribute copies of free software (and charge
30 | for this service if you wish); that you receive source code or can get
31 | it if you want it; that you can change the software and use pieces of
32 | it in new free programs; and that you are informed that you can do
33 | these things.
34 |
35 | To protect your rights, we need to make restrictions that forbid
36 | distributors to deny you these rights or to ask you to surrender these
37 | rights. These restrictions translate to certain responsibilities for
38 | you if you distribute copies of the library or if you modify it.
39 |
40 | For example, if you distribute copies of the library, whether gratis
41 | or for a fee, you must give the recipients all the rights that we gave
42 | you. You must make sure that they, too, receive or can get the source
43 | code. If you link other code with the library, you must provide
44 | complete object files to the recipients, so that they can relink them
45 | with the library after making changes to the library and recompiling
46 | it. And you must show them these terms so they know their rights.
47 |
48 | We protect your rights with a two-step method: (1) we copyright the
49 | library, and (2) we offer you this license, which gives you legal
50 | permission to copy, distribute and/or modify the library.
51 |
52 | To protect each distributor, we want to make it very clear that
53 | there is no warranty for the free library. Also, if the library is
54 | modified by someone else and passed on, the recipients should know
55 | that what they have is not the original version, so that the original
56 | author's reputation will not be affected by problems that might be
57 | introduced by others.
58 |
59 | Finally, software patents pose a constant threat to the existence of
60 | any free program. We wish to make sure that a company cannot
61 | effectively restrict the users of a free program by obtaining a
62 | restrictive license from a patent holder. Therefore, we insist that
63 | any patent license obtained for a version of the library must be
64 | consistent with the full freedom of use specified in this license.
65 |
66 | Most GNU software, including some libraries, is covered by the
67 | ordinary GNU General Public License. This license, the GNU Lesser
68 | General Public License, applies to certain designated libraries, and
69 | is quite different from the ordinary General Public License. We use
70 | this license for certain libraries in order to permit linking those
71 | libraries into non-free programs.
72 |
73 | When a program is linked with a library, whether statically or using
74 | a shared library, the combination of the two is legally speaking a
75 | combined work, a derivative of the original library. The ordinary
76 | General Public License therefore permits such linking only if the
77 | entire combination fits its criteria of freedom. The Lesser General
78 | Public License permits more lax criteria for linking other code with
79 | the library.
80 |
81 | We call this license the "Lesser" General Public License because it
82 | does Less to protect the user's freedom than the ordinary General
83 | Public License. It also provides other free software developers Less
84 | of an advantage over competing non-free programs. These disadvantages
85 | are the reason we use the ordinary General Public License for many
86 | libraries. However, the Lesser license provides advantages in certain
87 | special circumstances.
88 |
89 | For example, on rare occasions, there may be a special need to
90 | encourage the widest possible use of a certain library, so that it becomes
91 | a de-facto standard. To achieve this, non-free programs must be
92 | allowed to use the library. A more frequent case is that a free
93 | library does the same job as widely used non-free libraries. In this
94 | case, there is little to gain by limiting the free library to free
95 | software only, so we use the Lesser General Public License.
96 |
97 | In other cases, permission to use a particular library in non-free
98 | programs enables a greater number of people to use a large body of
99 | free software. For example, permission to use the GNU C Library in
100 | non-free programs enables many more people to use the whole GNU
101 | operating system, as well as its variant, the GNU/Linux operating
102 | system.
103 |
104 | Although the Lesser General Public License is Less protective of the
105 | users' freedom, it does ensure that the user of a program that is
106 | linked with the Library has the freedom and the wherewithal to run
107 | that program using a modified version of the Library.
108 |
109 | The precise terms and conditions for copying, distribution and
110 | modification follow. Pay close attention to the difference between a
111 | "work based on the library" and a "work that uses the library". The
112 | former contains code derived from the library, whereas the latter must
113 | be combined with the library in order to run.
114 |
115 | GNU LESSER GENERAL PUBLIC LICENSE
116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117 |
118 | 0. This License Agreement applies to any software library or other
119 | program which contains a notice placed by the copyright holder or
120 | other authorized party saying it may be distributed under the terms of
121 | this Lesser General Public License (also called "this License").
122 | Each licensee is addressed as "you".
123 |
124 | A "library" means a collection of software functions and/or data
125 | prepared so as to be conveniently linked with application programs
126 | (which use some of those functions and data) to form executables.
127 |
128 | The "Library", below, refers to any such software library or work
129 | which has been distributed under these terms. A "work based on the
130 | Library" means either the Library or any derivative work under
131 | copyright law: that is to say, a work containing the Library or a
132 | portion of it, either verbatim or with modifications and/or translated
133 | straightforwardly into another language. (Hereinafter, translation is
134 | included without limitation in the term "modification".)
135 |
136 | "Source code" for a work means the preferred form of the work for
137 | making modifications to it. For a library, complete source code means
138 | all the source code for all modules it contains, plus any associated
139 | interface definition files, plus the scripts used to control compilation
140 | and installation of the library.
141 |
142 | Activities other than copying, distribution and modification are not
143 | covered by this License; they are outside its scope. The act of
144 | running a program using the Library is not restricted, and output from
145 | such a program is covered only if its contents constitute a work based
146 | on the Library (independent of the use of the Library in a tool for
147 | writing it). Whether that is true depends on what the Library does
148 | and what the program that uses the Library does.
149 |
150 | 1. You may copy and distribute verbatim copies of the Library's
151 | complete source code as you receive it, in any medium, provided that
152 | you conspicuously and appropriately publish on each copy an
153 | appropriate copyright notice and disclaimer of warranty; keep intact
154 | all the notices that refer to this License and to the absence of any
155 | warranty; and distribute a copy of this License along with the
156 | Library.
157 |
158 | You may charge a fee for the physical act of transferring a copy,
159 | and you may at your option offer warranty protection in exchange for a
160 | fee.
161 |
162 | 2. You may modify your copy or copies of the Library or any portion
163 | of it, thus forming a work based on the Library, and copy and
164 | distribute such modifications or work under the terms of Section 1
165 | above, provided that you also meet all of these conditions:
166 |
167 | a) The modified work must itself be a software library.
168 |
169 | b) You must cause the files modified to carry prominent notices
170 | stating that you changed the files and the date of any change.
171 |
172 | c) You must cause the whole of the work to be licensed at no
173 | charge to all third parties under the terms of this License.
174 |
175 | d) If a facility in the modified Library refers to a function or a
176 | table of data to be supplied by an application program that uses
177 | the facility, other than as an argument passed when the facility
178 | is invoked, then you must make a good faith effort to ensure that,
179 | in the event an application does not supply such function or
180 | table, the facility still operates, and performs whatever part of
181 | its purpose remains meaningful.
182 |
183 | (For example, a function in a library to compute square roots has
184 | a purpose that is entirely well-defined independent of the
185 | application. Therefore, Subsection 2d requires that any
186 | application-supplied function or table used by this function must
187 | be optional: if the application does not supply it, the square
188 | root function must still compute square roots.)
189 |
190 | These requirements apply to the modified work as a whole. If
191 | identifiable sections of that work are not derived from the Library,
192 | and can be reasonably considered independent and separate works in
193 | themselves, then this License, and its terms, do not apply to those
194 | sections when you distribute them as separate works. But when you
195 | distribute the same sections as part of a whole which is a work based
196 | on the Library, the distribution of the whole must be on the terms of
197 | this License, whose permissions for other licensees extend to the
198 | entire whole, and thus to each and every part regardless of who wrote
199 | it.
200 |
201 | Thus, it is not the intent of this section to claim rights or contest
202 | your rights to work written entirely by you; rather, the intent is to
203 | exercise the right to control the distribution of derivative or
204 | collective works based on the Library.
205 |
206 | In addition, mere aggregation of another work not based on the Library
207 | with the Library (or with a work based on the Library) on a volume of
208 | a storage or distribution medium does not bring the other work under
209 | the scope of this License.
210 |
211 | 3. You may opt to apply the terms of the ordinary GNU General Public
212 | License instead of this License to a given copy of the Library. To do
213 | this, you must alter all the notices that refer to this License, so
214 | that they refer to the ordinary GNU General Public License, version 2,
215 | instead of to this License. (If a newer version than version 2 of the
216 | ordinary GNU General Public License has appeared, then you can specify
217 | that version instead if you wish.) Do not make any other change in
218 | these notices.
219 |
220 | Once this change is made in a given copy, it is irreversible for
221 | that copy, so the ordinary GNU General Public License applies to all
222 | subsequent copies and derivative works made from that copy.
223 |
224 | This option is useful when you wish to copy part of the code of
225 | the Library into a program that is not a library.
226 |
227 | 4. You may copy and distribute the Library (or a portion or
228 | derivative of it, under Section 2) in object code or executable form
229 | under the terms of Sections 1 and 2 above provided that you accompany
230 | it with the complete corresponding machine-readable source code, which
231 | must be distributed under the terms of Sections 1 and 2 above on a
232 | medium customarily used for software interchange.
233 |
234 | If distribution of object code is made by offering access to copy
235 | from a designated place, then offering equivalent access to copy the
236 | source code from the same place satisfies the requirement to
237 | distribute the source code, even though third parties are not
238 | compelled to copy the source along with the object code.
239 |
240 | 5. A program that contains no derivative of any portion of the
241 | Library, but is designed to work with the Library by being compiled or
242 | linked with it, is called a "work that uses the Library". Such a
243 | work, in isolation, is not a derivative work of the Library, and
244 | therefore falls outside the scope of this License.
245 |
246 | However, linking a "work that uses the Library" with the Library
247 | creates an executable that is a derivative of the Library (because it
248 | contains portions of the Library), rather than a "work that uses the
249 | library". The executable is therefore covered by this License.
250 | Section 6 states terms for distribution of such executables.
251 |
252 | When a "work that uses the Library" uses material from a header file
253 | that is part of the Library, the object code for the work may be a
254 | derivative work of the Library even though the source code is not.
255 | Whether this is true is especially significant if the work can be
256 | linked without the Library, or if the work is itself a library. The
257 | threshold for this to be true is not precisely defined by law.
258 |
259 | If such an object file uses only numerical parameters, data
260 | structure layouts and accessors, and small macros and small inline
261 | functions (ten lines or less in length), then the use of the object
262 | file is unrestricted, regardless of whether it is legally a derivative
263 | work. (Executables containing this object code plus portions of the
264 | Library will still fall under Section 6.)
265 |
266 | Otherwise, if the work is a derivative of the Library, you may
267 | distribute the object code for the work under the terms of Section 6.
268 | Any executables containing that work also fall under Section 6,
269 | whether or not they are linked directly with the Library itself.
270 |
271 | 6. As an exception to the Sections above, you may also combine or
272 | link a "work that uses the Library" with the Library to produce a
273 | work containing portions of the Library, and distribute that work
274 | under terms of your choice, provided that the terms permit
275 | modification of the work for the customer's own use and reverse
276 | engineering for debugging such modifications.
277 |
278 | You must give prominent notice with each copy of the work that the
279 | Library is used in it and that the Library and its use are covered by
280 | this License. You must supply a copy of this License. If the work
281 | during execution displays copyright notices, you must include the
282 | copyright notice for the Library among them, as well as a reference
283 | directing the user to the copy of this License. Also, you must do one
284 | of these things:
285 |
286 | a) Accompany the work with the complete corresponding
287 | machine-readable source code for the Library including whatever
288 | changes were used in the work (which must be distributed under
289 | Sections 1 and 2 above); and, if the work is an executable linked
290 | with the Library, with the complete machine-readable "work that
291 | uses the Library", as object code and/or source code, so that the
292 | user can modify the Library and then relink to produce a modified
293 | executable containing the modified Library. (It is understood
294 | that the user who changes the contents of definitions files in the
295 | Library will not necessarily be able to recompile the application
296 | to use the modified definitions.)
297 |
298 | b) Use a suitable shared library mechanism for linking with the
299 | Library. A suitable mechanism is one that (1) uses at run time a
300 | copy of the library already present on the user's computer system,
301 | rather than copying library functions into the executable, and (2)
302 | will operate properly with a modified version of the library, if
303 | the user installs one, as long as the modified version is
304 | interface-compatible with the version that the work was made with.
305 |
306 | c) Accompany the work with a written offer, valid for at
307 | least three years, to give the same user the materials
308 | specified in Subsection 6a, above, for a charge no more
309 | than the cost of performing this distribution.
310 |
311 | d) If distribution of the work is made by offering access to copy
312 | from a designated place, offer equivalent access to copy the above
313 | specified materials from the same place.
314 |
315 | e) Verify that the user has already received a copy of these
316 | materials or that you have already sent this user a copy.
317 |
318 | For an executable, the required form of the "work that uses the
319 | Library" must include any data and utility programs needed for
320 | reproducing the executable from it. However, as a special exception,
321 | the materials to be distributed need not include anything that is
322 | normally distributed (in either source or binary form) with the major
323 | components (compiler, kernel, and so on) of the operating system on
324 | which the executable runs, unless that component itself accompanies
325 | the executable.
326 |
327 | It may happen that this requirement contradicts the license
328 | restrictions of other proprietary libraries that do not normally
329 | accompany the operating system. Such a contradiction means you cannot
330 | use both them and the Library together in an executable that you
331 | distribute.
332 |
333 | 7. You may place library facilities that are a work based on the
334 | Library side-by-side in a single library together with other library
335 | facilities not covered by this License, and distribute such a combined
336 | library, provided that the separate distribution of the work based on
337 | the Library and of the other library facilities is otherwise
338 | permitted, and provided that you do these two things:
339 |
340 | a) Accompany the combined library with a copy of the same work
341 | based on the Library, uncombined with any other library
342 | facilities. This must be distributed under the terms of the
343 | Sections above.
344 |
345 | b) Give prominent notice with the combined library of the fact
346 | that part of it is a work based on the Library, and explaining
347 | where to find the accompanying uncombined form of the same work.
348 |
349 | 8. You may not copy, modify, sublicense, link with, or distribute
350 | the Library except as expressly provided under this License. Any
351 | attempt otherwise to copy, modify, sublicense, link with, or
352 | distribute the Library is void, and will automatically terminate your
353 | rights under this License. However, parties who have received copies,
354 | or rights, from you under this License will not have their licenses
355 | terminated so long as such parties remain in full compliance.
356 |
357 | 9. You are not required to accept this License, since you have not
358 | signed it. However, nothing else grants you permission to modify or
359 | distribute the Library or its derivative works. These actions are
360 | prohibited by law if you do not accept this License. Therefore, by
361 | modifying or distributing the Library (or any work based on the
362 | Library), you indicate your acceptance of this License to do so, and
363 | all its terms and conditions for copying, distributing or modifying
364 | the Library or works based on it.
365 |
366 | 10. Each time you redistribute the Library (or any work based on the
367 | Library), the recipient automatically receives a license from the
368 | original licensor to copy, distribute, link with or modify the Library
369 | subject to these terms and conditions. You may not impose any further
370 | restrictions on the recipients' exercise of the rights granted herein.
371 | You are not responsible for enforcing compliance by third parties with
372 | this License.
373 |
374 | 11. If, as a consequence of a court judgment or allegation of patent
375 | infringement or for any other reason (not limited to patent issues),
376 | conditions are imposed on you (whether by court order, agreement or
377 | otherwise) that contradict the conditions of this License, they do not
378 | excuse you from the conditions of this License. If you cannot
379 | distribute so as to satisfy simultaneously your obligations under this
380 | License and any other pertinent obligations, then as a consequence you
381 | may not distribute the Library at all. For example, if a patent
382 | license would not permit royalty-free redistribution of the Library by
383 | all those who receive copies directly or indirectly through you, then
384 | the only way you could satisfy both it and this License would be to
385 | refrain entirely from distribution of the Library.
386 |
387 | If any portion of this section is held invalid or unenforceable under any
388 | particular circumstance, the balance of the section is intended to apply,
389 | and the section as a whole is intended to apply in other circumstances.
390 |
391 | It is not the purpose of this section to induce you to infringe any
392 | patents or other property right claims or to contest validity of any
393 | such claims; this section has the sole purpose of protecting the
394 | integrity of the free software distribution system which is
395 | implemented by public license practices. Many people have made
396 | generous contributions to the wide range of software distributed
397 | through that system in reliance on consistent application of that
398 | system; it is up to the author/donor to decide if he or she is willing
399 | to distribute software through any other system and a licensee cannot
400 | impose that choice.
401 |
402 | This section is intended to make thoroughly clear what is believed to
403 | be a consequence of the rest of this License.
404 |
405 | 12. If the distribution and/or use of the Library is restricted in
406 | certain countries either by patents or by copyrighted interfaces, the
407 | original copyright holder who places the Library under this License may add
408 | an explicit geographical distribution limitation excluding those countries,
409 | so that distribution is permitted only in or among countries not thus
410 | excluded. In such case, this License incorporates the limitation as if
411 | written in the body of this License.
412 |
413 | 13. The Free Software Foundation may publish revised and/or new
414 | versions of the Lesser General Public License from time to time.
415 | Such new versions will be similar in spirit to the present version,
416 | but may differ in detail to address new problems or concerns.
417 |
418 | Each version is given a distinguishing version number. If the Library
419 | specifies a version number of this License which applies to it and
420 | "any later version", you have the option of following the terms and
421 | conditions either of that version or of any later version published by
422 | the Free Software Foundation. If the Library does not specify a
423 | license version number, you may choose any version ever published by
424 | the Free Software Foundation.
425 |
426 | 14. If you wish to incorporate parts of the Library into other free
427 | programs whose distribution conditions are incompatible with these,
428 | write to the author to ask for permission. For software which is
429 | copyrighted by the Free Software Foundation, write to the Free
430 | Software Foundation; we sometimes make exceptions for this. Our
431 | decision will be guided by the two goals of preserving the free status
432 | of all derivatives of our free software and of promoting the sharing
433 | and reuse of software generally.
434 |
435 | NO WARRANTY
436 |
437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446 |
447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456 | DAMAGES.
457 |
458 | END OF TERMS AND CONDITIONS
459 |
460 | How to Apply These Terms to Your New Libraries
461 |
462 | If you develop a new library, and you want it to be of the greatest
463 | possible use to the public, we recommend making it free software that
464 | everyone can redistribute and change. You can do so by permitting
465 | redistribution under these terms (or, alternatively, under the terms of the
466 | ordinary General Public License).
467 |
468 | To apply these terms, attach the following notices to the library. It is
469 | safest to attach them to the start of each source file to most effectively
470 | convey the exclusion of warranty; and each file should have at least the
471 | "copyright" line and a pointer to where the full notice is found.
472 |
473 |
474 | Copyright (C)
475 |
476 | This library is free software; you can redistribute it and/or
477 | modify it under the terms of the GNU Lesser General Public
478 | License as published by the Free Software Foundation; either
479 | version 2.1 of the License, or (at your option) any later version.
480 |
481 | This library is distributed in the hope that it will be useful,
482 | but WITHOUT ANY WARRANTY; without even the implied warranty of
483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 | Lesser General Public License for more details.
485 |
486 | You should have received a copy of the GNU Lesser General Public
487 | License along with this library; if not, write to the Free Software
488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489 |
490 | Also add information on how to contact you by electronic and paper mail.
491 |
492 | You should also get your employer (if you work as a programmer) or your
493 | school, if any, to sign a "copyright disclaimer" for the library, if
494 | necessary. Here is a sample; alter the names:
495 |
496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the
497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498 |
499 | , 1 April 1990
500 | Ty Coon, President of Vice
501 |
502 | That's all there is to it!
503 |
--------------------------------------------------------------------------------
/Resources/icons/PieMenu_Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
859 |
--------------------------------------------------------------------------------
/InitGui.py:
--------------------------------------------------------------------------------
1 | # PieMenu widget for FreeCAD
2 | #
3 | # Copyright (C) 2022, 2023 mdkus @ FreeCAD
4 | # Copyright (C) 2016, 2017 triplus @ FreeCAD
5 | # Copyright (C) 2015,2016 looo @ FreeCAD
6 | # Copyright (C) 2015 microelly
7 | #
8 | #
9 | # This library is free software; you can redistribute it and/or
10 | # modify it under the terms of the GNU Lesser General Public
11 | # License as published by the Free Software Foundation; either
12 | # version 2.1 of the License, or (at your option) any later version.
13 | #
14 | # This library is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | # Lesser General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU Lesser General Public
20 | # License along with this library; if not, write to the Free Software
21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 |
23 | # Attribution:
24 | # http://forum.freecadweb.org/
25 | # http://www.freecadweb.org/wiki/index.php?title=Code_snippets
26 |
27 | global PIE_MENU_VERSION
28 | PIE_MENU_VERSION = "1.2.7"
29 |
30 | def pieMenuStart():
31 | import math
32 | import operator
33 | import platform
34 | import FreeCAD as App
35 | import FreeCADGui as Gui
36 | from PySide import QtCore
37 | from PySide import QtGui
38 | import PieMenuLocator as locator
39 |
40 | path = locator.path()
41 | respath = path + "/Resources/icons/"
42 |
43 | # global status variables
44 | selectionTriggered = False
45 | contextPhase = False
46 |
47 | def remObsoleteParams():
48 | """Remove obsolete parameters from older versions."""
49 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
50 | paramGet.RemBool("ContextPhase")
51 |
52 | def accessoriesMenu():
53 | """Add pie menu preferences to accessories menu."""
54 | pref = QtGui.QAction(mw)
55 | pref.setText("Pie menu")
56 | pref.setObjectName("PieMenu")
57 | pref.triggered.connect(onPreferences)
58 | try:
59 | import AccessoriesMenu
60 | AccessoriesMenu.addItem("PieMenu")
61 | except ImportError:
62 | a = mw.findChild(QtGui.QAction, "AccessoriesMenu")
63 | if a:
64 | a.menu().addAction(pref)
65 | else:
66 | mb = mw.menuBar()
67 | action = QtGui.QAction(mw)
68 | action.setObjectName("AccessoriesMenu")
69 | action.setIconText("Accessories")
70 | menu = QtGui.QMenu()
71 | action.setMenu(menu)
72 | menu.addAction(pref)
73 |
74 | def addMenu():
75 | """Add accessories menu to the menu bar."""
76 | mb.addAction(action)
77 | action.setVisible(True)
78 |
79 | addMenu()
80 | mw.workbenchActivated.connect(addMenu)
81 |
82 |
83 | def onPreferences():
84 | """Open the preferences dialog."""
85 | onControl()
86 |
87 |
88 | styleButton = ("""
89 | QToolButton {
90 | background-color: lightGray;
91 | border: 1px outset silver;
92 | }
93 |
94 | QToolButton:disabled {
95 | background-color: darkGray;
96 | }
97 |
98 | QToolButton:hover {
99 | background-color: lightBlue;
100 | }
101 |
102 | QToolButton:checked {
103 | background-color: lightGreen;
104 | }
105 |
106 | QToolButton::menu-indicator {
107 | subcontrol-origin: padding;
108 | subcontrol-position: center center;
109 | }
110 |
111 | """)
112 |
113 | styleMenuClose = ("""
114 | QToolButton {
115 | background-color: rgba(60,60,60,255);
116 | color: silver;
117 | border: 1px solid #1e1e1e;
118 | }
119 |
120 | QToolButton::menu-indicator {
121 | image: none;
122 | }
123 |
124 | """)
125 |
126 | styleContainer = ("QMenu{background: transparent}")
127 |
128 | styleCombo = ("""
129 | QComboBox {
130 | background: transparent;
131 | border: 1px solid transparent;
132 | }
133 |
134 | """)
135 |
136 | styleQuickMenu = ("padding: 5px 10px 5px 10px")
137 |
138 | styleQuickMenuItem = ("""
139 | QMenu::item {
140 | padding: 5px 20px 5px 20px;
141 | }
142 |
143 | """)
144 |
145 | iconClose = respath + "PieMenuClose.svg"
146 | iconMenu = respath + "PieMenuQuickMenu.svg"
147 | iconUp = respath + "PieMenuUp.svg"
148 | iconDown = respath + "PieMenuDown.svg"
149 | iconAdd = respath + "PieMenuAdd.svg"
150 | iconRemove = respath + "PieMenuRemove.svg"
151 | iconRename = respath + "PieMenuRename.svg"
152 | iconCopy = respath + "PieMenuCopy.svg"
153 | iconRemoveCommand = respath + "PieMenuRemoveCommand.svg"
154 |
155 |
156 | def radiusSize(buttonSize):
157 |
158 | radius = str(math.trunc(buttonSize / 2))
159 |
160 | return "QToolButton {border-radius: " + radius + "px}"
161 |
162 |
163 | def iconSize(buttonSize):
164 |
165 | icon = buttonSize / 3 * 2
166 |
167 | return icon
168 |
169 |
170 | def closeButton(buttonSize=32):
171 |
172 | icon = iconSize(buttonSize)
173 | radius = radiusSize(buttonSize)
174 |
175 | button = QtGui.QToolButton()
176 | button.setProperty("ButtonX", 0)
177 | button.setProperty("ButtonY", 0)
178 | button.setGeometry(0, 0, buttonSize, buttonSize)
179 | button.setIconSize(QtCore.QSize(icon, icon))
180 | button.setIcon(QtGui.QIcon(iconClose))
181 | button.setStyleSheet(styleMenuClose + radius)
182 | button.setAttribute(QtCore.Qt.WA_TranslucentBackground)
183 |
184 | def onButton():
185 |
186 | PieMenuInstance.hide()
187 |
188 | button.clicked.connect(onButton)
189 |
190 | return button
191 |
192 |
193 | def quickMenu(buttonSize=20):
194 |
195 | icon = iconSize(buttonSize)
196 | radius = radiusSize(buttonSize)
197 |
198 | menu = QtGui.QMenu(mw)
199 | menu.setStyleSheet(styleQuickMenu)
200 |
201 | button = QtGui.QToolButton()
202 | button.setMenu(menu)
203 | button.setProperty("ButtonX", 0)
204 | button.setProperty("ButtonY", 32)
205 | button.setGeometry(0, 0, buttonSize, buttonSize)
206 | button.setStyleSheet(styleMenuClose + radius)
207 | button.setIconSize(QtCore.QSize(icon, icon))
208 | button.setIcon(QtGui.QIcon(iconMenu))
209 | button.setAttribute(QtCore.Qt.WA_TranslucentBackground)
210 | button.setPopupMode(QtGui.QToolButton
211 | .ToolButtonPopupMode.InstantPopup)
212 |
213 | menuMode = QtGui.QMenu()
214 | menuMode.setTitle("Trigger")
215 |
216 | modeGroup = QtGui.QActionGroup(menuMode)
217 | modeGroup.setExclusive(True)
218 |
219 | actionPress = QtGui.QAction(modeGroup)
220 | actionPress.setText("Press")
221 | actionPress.setData("Press")
222 | actionPress.setCheckable(True)
223 |
224 | actionHover = QtGui.QAction(modeGroup)
225 | actionHover.setText("Hover")
226 | actionHover.setData("Hover")
227 | actionHover.setCheckable(True)
228 |
229 | menuMode.addAction(actionPress)
230 | menuMode.addAction(actionHover)
231 |
232 | actionContext = QtGui.QAction(menu)
233 | actionContext.setText("Context")
234 | actionContext.setCheckable(True)
235 |
236 | menuPieMenu = QtGui.QMenu()
237 | menuPieMenu.setTitle("PieMenu")
238 |
239 | pieGroup = QtGui.QActionGroup(menu)
240 | pieGroup.setExclusive(True)
241 |
242 | menuToolBar = QtGui.QMenu()
243 | menuToolBar.setTitle("ToolBar")
244 | menuToolBar.setStyleSheet(styleQuickMenuItem)
245 |
246 | toolbarGroup = QtGui.QMenu()
247 |
248 | toolbarGroupOps = QtGui.QActionGroup(toolbarGroup)
249 | toolbarGroupOps.setExclusive(True)
250 |
251 | prefAction = QtGui.QAction(menu)
252 | prefAction.setIconText("Preferences")
253 |
254 | prefButton = QtGui.QToolButton()
255 | prefButton.setDefaultAction(prefAction)
256 |
257 | prefButtonWidgetAction = QtGui.QWidgetAction(menu)
258 | prefButtonWidgetAction.setDefaultWidget(prefButton)
259 |
260 | def setChecked():
261 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
262 |
263 | if paramGet.GetString("TriggerMode") == "Hover":
264 | actionHover.setChecked(True)
265 | else:
266 | actionPress.setChecked(True)
267 |
268 | if paramGet.GetBool("EnableContext"):
269 | actionContext.setChecked(True)
270 | else:
271 | pass
272 |
273 | setChecked()
274 |
275 | def onModeGroup():
276 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
277 | text = modeGroup.checkedAction().data()
278 | paramGet.SetString("TriggerMode", text)
279 |
280 | PieMenuInstance.hide()
281 | PieMenuInstance.showAtMouse(notKeyTriggered=True)
282 |
283 | modeGroup.triggered.connect(onModeGroup)
284 |
285 | def onActionContext():
286 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
287 |
288 | if actionContext.isChecked():
289 | paramGet.SetBool("EnableContext", True)
290 | contextList()
291 | else:
292 | paramGet.SetBool("EnableContext", False)
293 |
294 | addObserver()
295 |
296 | actionContext.triggered.connect(onActionContext)
297 |
298 | def pieList():
299 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
300 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
301 | indexList = paramIndexGet.GetString("IndexList")
302 |
303 | menuPieMenu.clear()
304 |
305 | if indexList:
306 | indexList = indexList.split(".,.")
307 |
308 | temp = []
309 |
310 | for i in indexList:
311 | temp.append(int(i))
312 |
313 | indexList = temp
314 | else:
315 | indexList = []
316 |
317 | pieList = []
318 |
319 | for i in indexList:
320 | a = str(i)
321 | try:
322 | pieName = paramIndexGet.GetString(a).decode("UTF-8")
323 | except AttributeError:
324 | pieName = paramIndexGet.GetString(a)
325 | pieList.append(pieName)
326 |
327 | if not paramGet.GetBool("ToolBar"):
328 | try:
329 | text = paramGet.GetString("CurrentPie").decode("UTF-8")
330 | except AttributeError:
331 | text = paramGet.GetString("CurrentPie")
332 | else:
333 | text = None
334 |
335 | for i in pieList:
336 | action = QtGui.QAction(pieGroup)
337 | action.setText(i)
338 | action.setCheckable(True)
339 |
340 | if i == text:
341 | action.setChecked(True)
342 | else:
343 | pass
344 |
345 | menuPieMenu.addAction(action)
346 |
347 | menuPieMenu.aboutToShow.connect(pieList)
348 |
349 | def onPieGroup():
350 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
351 |
352 | paramGet.SetBool("ToolBar", False)
353 | paramGet.RemString("ToolBar")
354 | try:
355 | text = pieGroup.checkedAction().text().encode("UTF-8")
356 | paramGet.SetString("CurrentPie", text)
357 | except TypeError:
358 | text = pieGroup.checkedAction().text()
359 | paramGet.SetString("CurrentPie", text)
360 |
361 | PieMenuInstance.hide()
362 | PieMenuInstance.showAtMouse(notKeyTriggered=True)
363 |
364 | pieGroup.triggered.connect(onPieGroup)
365 |
366 | def onMenuToolBar():
367 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
368 |
369 | menuToolBar.clear()
370 |
371 | if paramGet.GetBool("ToolBar"):
372 | text = paramGet.GetString("ToolBar")
373 | if ": " in text:
374 | toolbar_desc = text.split(": ")
375 | text = toolbar_desc[1]
376 | else:
377 | pass
378 | else:
379 | text = None
380 |
381 | for i in mw.findChildren(QtGui.QToolBar):
382 |
383 | commands = []
384 |
385 | for a in i.findChildren(QtGui.QToolButton):
386 | try:
387 | if not a.defaultAction().isSeparator():
388 | commands.append(a.defaultAction())
389 | else:
390 | pass
391 | except AttributeError:
392 | pass
393 |
394 | if len(commands) != 0:
395 | menu = QtGui.QMenu(i.windowTitle())
396 | menu.aboutToShow.connect(lambda sender=menu: onMenuToolbarGroup(sender))
397 | menuToolBar.addMenu(menu)
398 | else:
399 | pass
400 |
401 | menuToolBar.aboutToShow.connect(onMenuToolBar)
402 |
403 | def isActualPie(text):
404 |
405 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
406 | if paramGet.GetBool("ToolBar"):
407 | entry = paramGet.GetString("ToolBar")
408 | if ": " in entry:
409 | toolbar_desc = entry.split(": ")
410 | idMenu = toolbar_desc[1]
411 | else:
412 | idMenu = entry
413 | if idMenu == text:
414 | return True;
415 |
416 | return False
417 |
418 | def onMenuToolbarGroup(sender):
419 |
420 | if not sender.actions():
421 | action = QtGui.QAction(sender)
422 | action.setText("Show")
423 | action.setData(sender.title())
424 | action.setCheckable(True)
425 | if isActualPie(sender.title()):
426 | action.setChecked(True)
427 | sender.addAction(action)
428 |
429 | action = QtGui.QAction(sender)
430 | action.setText("Save")
431 | action.setData(sender.title())
432 | sender.addAction(action)
433 |
434 | sender.triggered.connect(lambda sender: onToolbarGroup(sender))
435 |
436 | def onToolbarGroup(sender):
437 |
438 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
439 | if sender.text() == "Show":
440 | paramGet.SetBool("ToolBar", True)
441 | elif sender.text() == "Save":
442 | newPieGroup = createPie(sender.data())
443 | else:
444 | return
445 |
446 | workbenches = []
447 | commands = []
448 |
449 | if sender.text() == "Save":
450 | # write persistent commands
451 | getGuiToolButtonData(sender.data(), None, commands, None)
452 | newPieGroup.SetString("ToolList", ".,.".join(commands))
453 | elif sender.text() == "Show":
454 | # write persistent toolbar and its workbenches
455 | getGuiToolButtonData(sender.data(), None, None, workbenches)
456 | toolbar_desc = ", ".join(workbenches)
457 | toolbar_desc = toolbar_desc + ': ' + sender.data()
458 | paramGet.SetString("ToolBar", toolbar_desc)
459 | PieMenuInstance.hide()
460 | PieMenuInstance.showAtMouse(notKeyTriggered=True)
461 |
462 | toolbarGroup.triggered.connect(onToolbarGroup)
463 |
464 | def onPrefButton():
465 |
466 | PieMenuInstance.hide()
467 | onControl()
468 |
469 | prefButton.clicked.connect(onPrefButton)
470 |
471 | menu.addMenu(menuMode)
472 | menu.addAction(actionContext)
473 | menu.addSeparator()
474 | menu.addMenu(menuPieMenu)
475 | menu.addMenu(menuToolBar)
476 | menu.addSeparator()
477 | menu.addAction(prefButtonWidgetAction)
478 |
479 | return button
480 |
481 |
482 | class HoverButton(QtGui.QToolButton):
483 |
484 | def __init__(self, parent=None):
485 | super(HoverButton, self).__init__()
486 |
487 | def enterEvent(self, event):
488 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
489 | mode = paramGet.GetString("TriggerMode")
490 | if self.defaultAction().isEnabled() and mode == "Hover":
491 | PieMenuInstance.hide()
492 | self.defaultAction().trigger()
493 | else:
494 | pass
495 |
496 | def mouseReleaseEvent(self, event):
497 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
498 | mode = paramGet.GetString("TriggerMode")
499 |
500 | if self.defaultAction().isEnabled():
501 | PieMenuInstance.hide()
502 | self.defaultAction().trigger()
503 | else:
504 | pass
505 |
506 |
507 | class PieMenu:
508 |
509 | def __init__(self):
510 |
511 | self.radius = 100
512 | self.buttons = []
513 | self.buttonSize = 32
514 | self.menu = QtGui.QMenu(mw)
515 | self.menuSize = 0
516 | self.menu.setStyleSheet(styleContainer)
517 | self.menu.setWindowFlags(self.menu.windowFlags() | QtCore.Qt.FramelessWindowHint)
518 | self.menu.setAttribute(QtCore.Qt.WA_TranslucentBackground)
519 |
520 | if compositingManager:
521 | pass
522 | else:
523 | self.menu.setAttribute(QtCore.Qt.WA_PaintOnScreen)
524 |
525 | def add_commands(self, commands, context=False):
526 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
527 |
528 | for i in self.buttons:
529 | i.deleteLater()
530 |
531 | self.buttons = []
532 |
533 | if context:
534 | group = getGroup(mode=2)
535 | else:
536 | group = getGroup(mode=1)
537 |
538 | if len(commands) == 0:
539 | commandNumber = 1
540 | else:
541 | commandNumber = len(commands)
542 |
543 | valueRadius = group.GetInt("Radius")
544 | valueButton = group.GetInt("Button")
545 |
546 | if paramGet.GetBool("ToolBar"):
547 | valueRadius = 100
548 | valueButton = 32
549 |
550 | if valueRadius:
551 | self.radius = valueRadius
552 | else:
553 | self.radius = 100
554 |
555 | if valueButton:
556 | self.buttonSize = valueButton
557 | else:
558 | self.buttonSize = 32
559 |
560 | if commandNumber == 1:
561 | angle = 0
562 | buttonSize = self.buttonSize
563 | else:
564 | angle = 2 * math.pi / commandNumber
565 | buttonRadius = math.sin(angle / 2) * self.radius
566 | buttonSize = math.trunc(2 * buttonRadius / math.sqrt(2))
567 |
568 | angleStart = 3 * math.pi / 2 - angle
569 |
570 | if buttonSize > self.buttonSize:
571 | buttonSize = self.buttonSize
572 | else:
573 | pass
574 |
575 | radius = radiusSize(buttonSize)
576 | icon = iconSize(buttonSize)
577 |
578 | if windowShadow:
579 | pass
580 | else:
581 | self.menuSize = valueRadius * 2 + buttonSize + 4
582 |
583 | if self.menuSize < 90:
584 | self.menuSize = 90
585 | else:
586 | pass
587 |
588 | self.menu.setMinimumWidth(self.menuSize)
589 | self.menu.setMinimumHeight(self.menuSize)
590 |
591 | num = 1
592 |
593 | for i in commands:
594 |
595 | button = HoverButton()
596 | button.setParent(self.menu)
597 | button.setAttribute(QtCore.Qt.WA_Hover)
598 | button.setStyleSheet(styleButton + radius)
599 | button.setAttribute(QtCore.Qt.WA_TranslucentBackground)
600 | button.setDefaultAction(commands[commands.index(i)])
601 | button.setGeometry(0, 0, buttonSize, buttonSize)
602 | button.setIconSize(QtCore.QSize(icon, icon))
603 | button.setProperty("ButtonX", self.radius *
604 | (math.cos(angle * num + angleStart)))
605 | button.setProperty("ButtonY", self.radius *
606 | (math.sin(angle * num + angleStart)))
607 |
608 | self.buttons.append(button)
609 |
610 | num = num + 1
611 |
612 | buttonQuickMenu = quickMenu()
613 | buttonQuickMenu.setParent(self.menu)
614 | self.buttons.append(buttonQuickMenu)
615 |
616 | buttonClose = closeButton()
617 | buttonClose.setParent(self.menu)
618 | self.buttons.append(buttonClose)
619 |
620 | if compositingManager:
621 | pass
622 | else:
623 | for i in self.buttons:
624 | i.setAttribute(QtCore.Qt.WA_PaintOnScreen)
625 |
626 | def hide(self):
627 | for i in self.buttons:
628 | i.hide()
629 |
630 | self.menu.hide()
631 |
632 | def showAtMouse(self, notKeyTriggered=False):
633 |
634 | nonlocal selectionTriggered
635 | nonlocal contextPhase
636 | global lastPosX
637 | global lastPosY
638 |
639 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
640 |
641 | enableContext = paramGet.GetBool("EnableContext")
642 |
643 | if contextPhase:
644 | sel = Gui.Selection.getSelectionEx()
645 | if not sel:
646 | self.hide()
647 | contextPhase = False
648 | updateCommands()
649 | elif not enableContext:
650 | self.hide()
651 | updateCommands()
652 | else:
653 | updateCommands(context=True)
654 | else:
655 | updateCommands()
656 |
657 | if self.menu.isVisible():
658 | self.hide()
659 | else:
660 | if windowShadow:
661 | pos = mw.mapFromGlobal(QtGui.QCursor.pos())
662 | if notKeyTriggered:
663 | if contextPhase:
664 | # special case treatment
665 | if selectionTriggered:
666 | selectionTriggered = False
667 | else:
668 | pos.setX(lastPosX)
669 | pos.setY(lastPosY)
670 | lastPosX = pos.x()
671 | lastPosY = pos.y()
672 | else:
673 | pos.setX(lastPosX)
674 | pos.setY(lastPosY)
675 | else:
676 | lastPosX = pos.x()
677 | lastPosY = pos.y()
678 |
679 | self.menu.popup(QtCore.QPoint(mw.pos()))
680 | self.menu.setGeometry(mw.geometry())
681 |
682 | for i in self.buttons:
683 | i.move(i.property("ButtonX") + pos.x() - i.width() / 2,
684 | i.property("ButtonY") + pos.y() - i.height() / 2)
685 |
686 | i.setVisible(True)
687 |
688 | for i in self.buttons:
689 | i.repaint()
690 | else:
691 | pos = QtGui.QCursor.pos()
692 | if notKeyTriggered:
693 | if contextPhase:
694 | # special case treatment
695 | if selectionTriggered:
696 | selectionTriggered = False
697 | else:
698 | pos.setX(lastPosX)
699 | pos.setY(lastPosY)
700 | lastPosX = pos.x()
701 | lastPosY = pos.y()
702 | else:
703 | pos.setX(lastPosX)
704 | pos.setY(lastPosY)
705 | else:
706 | lastPosX = pos.x()
707 | lastPosY = pos.y()
708 |
709 | for i in self.buttons:
710 | i.move(i.property("ButtonX") + (self.menuSize - i.size().width()) / 2,
711 | i.property("ButtonY") + (self.menuSize - i.size().height()) / 2)
712 |
713 | i.setVisible(True)
714 |
715 | self.menu.popup(QtCore.QPoint(pos.x() - self.menuSize / 2, pos.y() - self.menuSize / 2))
716 |
717 |
718 | sign = {
719 | "<": operator.lt,
720 | "<=": operator.le,
721 | "==": operator.eq,
722 | "!=": operator.ne,
723 | ">": operator.gt,
724 | ">=": operator.ge,
725 | }
726 |
727 |
728 | def contextList():
729 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
730 | indexList = paramIndexGet.GetString("IndexList")
731 |
732 | contextAll.clear()
733 |
734 | if indexList:
735 | indexList = indexList.split(".,.")
736 |
737 | temp = []
738 |
739 | for i in indexList:
740 | temp.append(int(i))
741 |
742 | indexList = temp
743 | else:
744 | indexList = []
745 |
746 | for i in indexList:
747 | a = str(i)
748 | group = paramIndexGet.GetGroup(a)
749 | groupContext = group.GetGroup("Context")
750 |
751 | if groupContext.GetBool("Enabled"):
752 |
753 | current = {}
754 |
755 | current["Index"] = a
756 |
757 | current["VertexSign"] = groupContext.GetString("VertexSign")
758 | current["VertexValue"] = groupContext.GetInt("VertexValue")
759 |
760 | current["EdgeSign"] = groupContext.GetString("EdgeSign")
761 | current["EdgeValue"] = groupContext.GetInt("EdgeValue")
762 |
763 | current["FaceSign"] = groupContext.GetString("FaceSign")
764 | current["FaceValue"] = groupContext.GetInt("FaceValue")
765 |
766 | current["ObjectSign"] = groupContext.GetString("ObjectSign")
767 | current["ObjectValue"] = groupContext.GetInt("ObjectValue")
768 |
769 | contextAll[i] = current
770 |
771 | else:
772 | pass
773 |
774 |
775 | def getContextPie(v, e, f, o):
776 | global globalContextPie
777 | global globalIndexPie
778 |
779 | globalContextPie = False
780 | globalIndexPie = None
781 |
782 | for i in contextAll:
783 |
784 | current = contextAll[i]
785 |
786 | def vertex():
787 | if sign[current["VertexSign"]](v, current["VertexValue"]):
788 | edge()
789 | else:
790 | pass
791 |
792 | def edge():
793 | if sign[current["EdgeSign"]](e, current["EdgeValue"]):
794 | face()
795 | else:
796 | pass
797 |
798 | def face():
799 | if sign[current["FaceSign"]](f, current["FaceValue"]):
800 | obj()
801 | else:
802 | pass
803 |
804 | def obj():
805 | if sign[current["ObjectSign"]](o, current["ObjectValue"]):
806 | global globalContextPie
807 | global globalIndexPie
808 |
809 | globalContextPie = "True"
810 | globalIndexPie = current["Index"]
811 | else:
812 | pass
813 |
814 | vertex()
815 |
816 | if globalContextPie == "True":
817 | return globalIndexPie
818 | else:
819 | return None
820 |
821 |
822 | def listTopo():
823 |
824 | nonlocal selectionTriggered
825 | nonlocal contextPhase
826 |
827 | sel = Gui.Selection.getSelectionEx()
828 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
829 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
830 |
831 | vertexes = 0
832 | edges = 0
833 | faces = 0
834 | objects = 0
835 |
836 | allList = []
837 |
838 | for i in sel:
839 | if not i.SubElementNames:
840 | objects = objects + 1
841 | else:
842 | for a in i.SubElementNames:
843 | allList.append(a)
844 |
845 | for i in allList:
846 | if i.startswith('Vertex'):
847 | vertexes = vertexes + 1
848 | elif i.startswith('Edge'):
849 | edges = edges + 1
850 | elif i.startswith('Face'):
851 | faces = faces + 1
852 | else:
853 | pass
854 |
855 | pieIndex = getContextPie(vertexes,
856 | edges,
857 | faces,
858 | objects)
859 |
860 | if pieIndex:
861 | try:
862 | pieName = paramIndexGet.GetString(pieIndex).decode("UTF-8")
863 | except AttributeError:
864 | pieName = paramIndexGet.GetString(pieIndex)
865 | try:
866 | paramGet.SetString("ContextPie", pieName.encode("UTF-8"))
867 | except TypeError:
868 | paramGet.SetString("ContextPie", pieName)
869 | contextPhase = True
870 |
871 | updateCommands(context=True)
872 | PieMenuInstance.hide()
873 | selectionTriggered = True
874 | PieMenuInstance.showAtMouse(notKeyTriggered=True)
875 | else:
876 | pass
877 |
878 |
879 | class SelObserver:
880 |
881 | def addSelection(self, doc, obj, sub, pnt):
882 |
883 | listTopo()
884 |
885 | def removeSelection(self, doc, obj, sub):
886 |
887 | listTopo()
888 |
889 |
890 | def addObserver():
891 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
892 |
893 | if paramGet.GetBool("EnableContext"):
894 | Gui.Selection.addObserver(selObserver)
895 | else:
896 | Gui.Selection.removeObserver(selObserver)
897 |
898 |
899 | def getGuiActionMapAll():
900 |
901 | actions = {}
902 | duplicates = []
903 |
904 | for i in mw.findChildren(QtGui.QAction):
905 | if i.objectName() is not None:
906 | if i.objectName() != "" and i.icon():
907 | if i.objectName() in actions:
908 | if i.objectName() not in duplicates:
909 | duplicates.append(i.objectName())
910 | else:
911 | pass
912 | else:
913 | actions[i.objectName()] = i
914 | else:
915 | pass
916 | else:
917 | pass
918 |
919 | for d in duplicates:
920 | del actions[d]
921 |
922 | return actions
923 |
924 |
925 | def extractWorkbench(command):
926 |
927 | cmd_parts = command.split("_")
928 | if cmd_parts[0] == "":
929 | workbench = "None"
930 | else:
931 | workbench = cmd_parts[0]
932 |
933 | return workbench
934 |
935 |
936 | def getActionData(action, actions, commands, workbenches):
937 |
938 | if not action.icon():
939 | return
940 | if actions is not None:
941 | if action in actions:
942 | pass
943 | else:
944 | actions.append(action)
945 | if commands is None and workbenches is None:
946 | return
947 |
948 | command = action.objectName()
949 | if len(command) == 0:
950 | workbench = "None"
951 | else:
952 | if commands is not None:
953 | if command in commands:
954 | pass
955 | else:
956 | commands.append(command)
957 | workbench = extractWorkbench(command)
958 |
959 | if workbenches is not None:
960 | if not workbench in workbenches:
961 | workbenches.append(workbench)
962 |
963 |
964 | def getGuiToolButtonData(idToolBar, actions, commands, workbenches):
965 |
966 | actionMapAll = getGuiActionMapAll()
967 | for i in actionMapAll:
968 | action = actionMapAll[i]
969 | for widgets in action.associatedWidgets():
970 | if widgets.objectName() == idToolBar:
971 | getActionData(action, actions, commands, workbenches)
972 |
973 |
974 | def actualizeWorkbenchActions(actions, toolList, actionMap):
975 | for i in toolList:
976 | # rule out special case: there has to be an entry
977 | if i == "":
978 | pass
979 | elif i in actionMap:
980 | if not actionMap[i] in actions:
981 | actions.append(actionMap[i])
982 | else:
983 | cmd_parts = i.split("_")
984 | # rule out special case: unknown Std action
985 | if cmd_parts[0] == "Std":
986 | pass
987 | else:
988 | # match special cases
989 | # Fem workbench
990 | if cmd_parts[0] == "FEM":
991 | cmd_parts[0] = "Fem"
992 | # Sheet Metal workbench
993 | if cmd_parts[0][:2] == "SM":
994 | cmd_parts[0] = cmd_parts[0][:2]
995 |
996 | cmdWb = cmd_parts[0] + "Workbench"
997 | # after workbench activation actionMap has to be actualized
998 | Gui.activateWorkbench(cmdWb)
999 | return True
1000 |
1001 | return False
1002 |
1003 |
1004 | def updateCommands(context=False):
1005 |
1006 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1007 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1008 | indexList = paramIndexGet.GetString("IndexList")
1009 |
1010 | if paramGet.GetBool("ToolBar") and context is False:
1011 |
1012 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1013 | toolbar = paramGet.GetString("ToolBar")
1014 |
1015 | if ": " in toolbar:
1016 | toolbar_desc = toolbar.split(": ")
1017 | toolbar = toolbar_desc[1]
1018 | workbenches = toolbar_desc[0]
1019 | workbenches = workbenches.split(", ")
1020 | lastWorkbench = Gui.activeWorkbench()
1021 |
1022 | for i in workbenches:
1023 | # rule out special cases
1024 | if i == "None" or i == "Std":
1025 | pass
1026 | else:
1027 | # match special cases
1028 | # Fem workbench
1029 | if i == "FEM":
1030 | i = "Fem"
1031 | # Sheet Metal workbench
1032 | if i[:2] == "SM":
1033 | i = i[:2]
1034 |
1035 | Gui.activateWorkbench(i + "Workbench")
1036 |
1037 | Gui.activateWorkbench(lastWorkbench.__class__.__name__)
1038 | else:
1039 | pass
1040 |
1041 | actions = []
1042 | getGuiToolButtonData(toolbar, actions, None, None)
1043 |
1044 | else:
1045 |
1046 | if indexList:
1047 | indexList = indexList.split(".,.")
1048 |
1049 | temp = []
1050 |
1051 | for i in indexList:
1052 | temp.append(int(i))
1053 |
1054 | indexList = temp
1055 | else:
1056 | indexList = []
1057 |
1058 | if context:
1059 | try:
1060 | text = paramGet.GetString("ContextPie").decode("UTF-8")
1061 | except AttributeError:
1062 | text = paramGet.GetString("ContextPie")
1063 | else:
1064 | try:
1065 | text = paramGet.GetString("CurrentPie").decode("UTF-8")
1066 | except AttributeError:
1067 | text = paramGet.GetString("CurrentPie")
1068 |
1069 | toolList = None
1070 |
1071 | for i in indexList:
1072 | a = str(i)
1073 | try:
1074 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1075 | except AttributeError:
1076 | pie = paramIndexGet.GetString(a)
1077 | if pie == text:
1078 | group = paramIndexGet.GetGroup(a)
1079 | toolList = group.GetString("ToolList")
1080 | else:
1081 | pass
1082 |
1083 | if toolList:
1084 | toolList = toolList.split(".,.")
1085 | else:
1086 | toolList = []
1087 |
1088 | actions = []
1089 |
1090 | actionMapAll = getGuiActionMapAll()
1091 | lastWorkbench = Gui.activeWorkbench()
1092 |
1093 | while actualizeWorkbenchActions(actions, toolList, actionMapAll):
1094 | actionMapAll = getGuiActionMapAll()
1095 | else:
1096 | pass
1097 |
1098 | Gui.activateWorkbench(lastWorkbench.__class__.__name__)
1099 |
1100 | PieMenuInstance.add_commands(actions, context)
1101 |
1102 |
1103 | def getGroup(mode=0):
1104 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1105 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1106 | indexList = paramIndexGet.GetString("IndexList")
1107 |
1108 | if mode == 2:
1109 | try:
1110 | text = paramGet.GetString("ContextPie").decode("UTF-8")
1111 | except AttributeError:
1112 | text = paramGet.GetString("ContextPie")
1113 | elif mode == 1:
1114 | try:
1115 | text = paramGet.GetString("CurrentPie").decode("UTF-8")
1116 | except AttributeError:
1117 | text = paramGet.GetString("CurrentPie")
1118 | else:
1119 | text = cBox.currentText()
1120 |
1121 | if indexList:
1122 | indexList = indexList.split(".,.")
1123 |
1124 | temp = []
1125 |
1126 | for i in indexList:
1127 | temp.append(int(i))
1128 |
1129 | indexList = temp
1130 | else:
1131 | indexList = []
1132 |
1133 | group = None
1134 |
1135 | for i in indexList:
1136 | a = str(i)
1137 | try:
1138 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1139 | except AttributeError:
1140 | pie = paramIndexGet.GetString(a)
1141 |
1142 | if pie == text:
1143 | group = paramIndexGet.GetGroup(a)
1144 | else:
1145 | pass
1146 |
1147 | if group:
1148 | pass
1149 | else:
1150 | if 0 in indexList:
1151 | group = paramIndexGet.GetGroup("0")
1152 | else:
1153 | setDefaultPie()
1154 | updateCommands()
1155 | group = paramIndexGet.GetGroup("0")
1156 |
1157 | return group
1158 |
1159 | buttonListWidget = QtGui.QListWidget()
1160 | buttonListWidget.setHorizontalScrollBarPolicy(QtCore
1161 | .Qt.ScrollBarAlwaysOff)
1162 |
1163 |
1164 | def buttonList():
1165 |
1166 | group = getGroup()
1167 | toolList = group.GetString("ToolList")
1168 |
1169 | if toolList:
1170 | toolList = toolList.split(".,.")
1171 | else:
1172 | toolList = []
1173 |
1174 | actionMapAll = getGuiActionMapAll()
1175 |
1176 | buttonListWidget.blockSignals(True)
1177 |
1178 | buttonListWidget.clear()
1179 |
1180 | workbenches = []
1181 | lastWorkbench = Gui.activeWorkbench()
1182 |
1183 | for i in toolList:
1184 | if i not in actionMapAll:
1185 | # rule out special case: there has to be an entry
1186 | if i == "":
1187 | pass
1188 | else:
1189 | cmd_parts = i.split("_")
1190 | if cmd_parts[0] not in workbenches:
1191 | # rule out special case: unknown Std action
1192 | if cmd_parts[0] == "Std":
1193 | pass
1194 | else:
1195 | # treatment of special cases
1196 | # Fem workbench
1197 | if cmd_parts[0] == "FEM":
1198 | cmd_parts[0] = "Fem"
1199 | # Sheet Metal workbench
1200 | if cmd_parts[0][:2] == "SM":
1201 | cmd_parts[0] = cmd_parts[0][:2]
1202 | workbenches.append(cmd_parts[0])
1203 | Gui.activateWorkbench(cmd_parts[0] + "Workbench")
1204 | else:
1205 | pass
1206 | else:
1207 | pass
1208 |
1209 | Gui.activateWorkbench(lastWorkbench.__class__.__name__)
1210 | actionMapAll = getGuiActionMapAll()
1211 |
1212 | for i in toolList:
1213 | if i in actionMapAll:
1214 | item = QtGui.QListWidgetItem(buttonListWidget)
1215 | item.setData(QtCore.Qt.UserRole, i)
1216 | item.setText(actionMapAll[i].text().replace("&", ""))
1217 | item.setIcon(actionMapAll[i].icon())
1218 | else:
1219 | pass
1220 |
1221 | buttonListWidget.blockSignals(False)
1222 |
1223 |
1224 | cBox = QtGui.QComboBox()
1225 | cBox.setMinimumHeight(30)
1226 |
1227 |
1228 | def cBoxUpdate():
1229 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1230 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1231 | indexList = paramIndexGet.GetString("IndexList")
1232 | try:
1233 | currentPie = paramGet.GetString("CurrentPie").decode("UTF-8")
1234 | except AttributeError:
1235 | currentPie = paramGet.GetString("CurrentPie")
1236 |
1237 | if indexList:
1238 | indexList = indexList.split(".,.")
1239 |
1240 | temp = []
1241 |
1242 | for i in indexList:
1243 | temp.append(int(i))
1244 |
1245 | indexList = temp
1246 | else:
1247 | indexList = []
1248 |
1249 | pieList = []
1250 |
1251 | for i in indexList:
1252 | a = str(i)
1253 | try:
1254 | pieList.append(paramIndexGet.GetString(a).decode("UTF-8"))
1255 | except AttributeError:
1256 | pieList.append(paramIndexGet.GetString(a))
1257 |
1258 | duplicates = []
1259 | for i in pieList:
1260 | if i == currentPie:
1261 | pass
1262 | else:
1263 | duplicates.append(i)
1264 | duplicates.append(currentPie)
1265 | pieList = duplicates
1266 |
1267 | pieList.reverse()
1268 |
1269 | cBox.blockSignals(True)
1270 |
1271 | cBox.clear()
1272 |
1273 | for i in pieList:
1274 | cBox.insertItem(0, i)
1275 |
1276 | cBox.blockSignals(False)
1277 |
1278 | onPieChange()
1279 |
1280 |
1281 | def onPieChange():
1282 | buttonList()
1283 | toolList()
1284 | setDefaults()
1285 | setCheckContext()
1286 |
1287 | cBox.currentIndexChanged.connect(onPieChange)
1288 |
1289 | buttonAddPieMenu = QtGui.QToolButton()
1290 | buttonAddPieMenu.setIcon(QtGui.QIcon(iconAdd))
1291 | buttonAddPieMenu.setToolTip("Add new pie menu")
1292 | buttonAddPieMenu.setMinimumHeight(30)
1293 | buttonAddPieMenu.setMinimumWidth(30)
1294 |
1295 |
1296 | def inputTextDialog(title):
1297 |
1298 | info1 = "Please insert menu name"
1299 | info2 = "Menu already exists"
1300 |
1301 | d = QtGui.QInputDialog(pieMenuDialog)
1302 | d.setModal(True)
1303 | d.setInputMode(QtGui.QInputDialog.InputMode.TextInput)
1304 | text, ok = QtGui.QInputDialog.getText(pieMenuDialog,
1305 | title,
1306 | info1)
1307 | if not ok:
1308 | return text, ok
1309 |
1310 | while not text:
1311 | text, ok = QtGui.QInputDialog.getText(pieMenuDialog,
1312 | title,
1313 | info1)
1314 | if not ok:
1315 | return text, ok
1316 | else:
1317 | pass
1318 |
1319 | index = cBox.findText(text)
1320 | info = info2
1321 |
1322 | while index != -1:
1323 | d = QtGui.QInputDialog(pieMenuDialog)
1324 | d.setModal(True)
1325 | d.setInputMode(QtGui.QInputDialog.InputMode.TextInput)
1326 | text, ok = QtGui.QInputDialog.getText(pieMenuDialog,
1327 | title,
1328 | info)
1329 | if ok:
1330 | if text:
1331 | index = cBox.findText(text)
1332 | info = info2
1333 | else:
1334 | info = info1
1335 | else:
1336 | return text, ok
1337 |
1338 | return text, ok
1339 |
1340 |
1341 | def splitIndexList(indexList):
1342 |
1343 | if indexList:
1344 | indexList = indexList.split(".,.")
1345 |
1346 | temp = []
1347 |
1348 | for i in indexList:
1349 | temp.append(int(i))
1350 |
1351 | indexList = temp
1352 | else:
1353 | indexList = []
1354 |
1355 | return indexList
1356 |
1357 |
1358 | def createPie(text):
1359 |
1360 |
1361 |
1362 |
1363 |
1364 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1365 | indexList = paramIndexGet.GetString("IndexList")
1366 | indexList = splitIndexList(indexList)
1367 |
1368 | pieList = []
1369 |
1370 | for i in indexList:
1371 | a = str(i)
1372 | pieList.append(paramIndexGet.GetString(a))
1373 |
1374 | if text.encode('UTF-8') in pieList:
1375 | pass
1376 | elif not text:
1377 | pass
1378 | else:
1379 |
1380 | if text == "restore_default_pie" and text.lower():
1381 | setDefaultPie(restore=True)
1382 | else:
1383 | x = 1
1384 |
1385 | while x in indexList and x < 999:
1386 | x = x + 1
1387 | else:
1388 | indexNumber = x
1389 |
1390 | indexList.append(indexNumber)
1391 |
1392 | temp = []
1393 |
1394 | for i in indexList:
1395 | temp.append(str(i))
1396 |
1397 | indexList = temp
1398 |
1399 | paramIndexGet.SetString("IndexList", ".,.".join(indexList))
1400 |
1401 | indexNumber = str(indexNumber)
1402 | try:
1403 | paramIndexGet.SetString(indexNumber, text.encode('UTF-8'))
1404 | except TypeError:
1405 | paramIndexGet.SetString(indexNumber, text)
1406 |
1407 | cBoxUpdate()
1408 |
1409 | return paramIndexGet.GetGroup(indexNumber)
1410 |
1411 |
1412 | def onButtonAddPieMenu():
1413 |
1414 | text, ok = inputTextDialog("New menu")
1415 | if not ok:
1416 | return
1417 |
1418 | createPie(text)
1419 |
1420 |
1421 | buttonAddPieMenu.clicked.connect(onButtonAddPieMenu)
1422 |
1423 | buttonRemovePieMenu = QtGui.QToolButton()
1424 | buttonRemovePieMenu.setIcon(QtGui.QIcon(iconRemove))
1425 | buttonRemovePieMenu.setToolTip("Remove current pie menu")
1426 | buttonRemovePieMenu.setMinimumHeight(30)
1427 | buttonRemovePieMenu.setMinimumWidth(30)
1428 |
1429 |
1430 | def onButtonRemovePieMenu():
1431 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1432 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1433 | indexList = paramIndexGet.GetString("IndexList")
1434 | indexList = splitIndexList(indexList)
1435 | try:
1436 | currentPie = paramGet.GetString("CurrentPie").decode("UTF-8")
1437 | except AttributeError:
1438 | currentPie = paramGet.GetString("CurrentPie")
1439 | try:
1440 | contextPie = paramGet.GetString("ContextPie").decode("UTF-8")
1441 | except AttributeError:
1442 | contextPie = paramGet.GetString("ContextPie")
1443 |
1444 | text = cBox.currentText()
1445 |
1446 | for i in indexList:
1447 | a = str(i)
1448 | try:
1449 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1450 | except AttributeError:
1451 | pie = paramIndexGet.GetString(a)
1452 | if pie == text:
1453 | indexList.remove(i)
1454 |
1455 | temp = []
1456 |
1457 | for i in indexList:
1458 | temp.append(str(i))
1459 |
1460 | indexList = temp
1461 |
1462 | paramIndexGet.SetString("IndexList", ".,.".join(indexList))
1463 |
1464 | paramIndexGet.RemGroup(a)
1465 | paramIndexGet.RemString(a)
1466 | # special case treatment
1467 | if pie == currentPie:
1468 | currentPie = "Default"
1469 | try:
1470 | paramGet.SetString("CurrentPie", currentPie.encode('UTF-8'))
1471 | except TypeError:
1472 | paramGet.SetString("CurrentPie", currentPie)
1473 | if pie == contextPie:
1474 | paramGet.RemString("ContextPie")
1475 | else:
1476 | pass
1477 |
1478 | cBoxUpdate()
1479 |
1480 | if cBox.currentIndex() == -1:
1481 | setDefaultPie()
1482 | cBoxUpdate()
1483 | else:
1484 | pass
1485 |
1486 | buttonRemovePieMenu.clicked.connect(onButtonRemovePieMenu)
1487 |
1488 | buttonRenamePieMenu = QtGui.QToolButton()
1489 | buttonRenamePieMenu.setToolTip("Rename current pie menu")
1490 | buttonRenamePieMenu.setIcon(QtGui.QIcon(iconRename))
1491 | buttonRenamePieMenu.setMinimumHeight(30)
1492 | buttonRenamePieMenu.setMinimumWidth(30)
1493 |
1494 |
1495 | def onButtonRenamePieMenu():
1496 |
1497 | text, ok = inputTextDialog("Rename menu")
1498 | if not ok:
1499 | return
1500 |
1501 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
1502 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1503 | indexList = paramIndexGet.GetString("IndexList")
1504 | indexList = splitIndexList(indexList)
1505 | try:
1506 | currentPie = paramGet.GetString("CurrentPie").decode("UTF-8")
1507 | except AttributeError:
1508 | currentPie = paramGet.GetString("CurrentPie")
1509 | currentText = cBox.currentText()
1510 |
1511 | for i in indexList:
1512 | a = str(i)
1513 | try:
1514 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1515 | except AttributeError:
1516 | pie = paramIndexGet.GetString(a)
1517 | if pie == currentText:
1518 | try:
1519 | paramIndexGet.SetString(a, text.encode('UTF-8'))
1520 | except TypeError:
1521 | paramIndexGet.SetString(a, text)
1522 | if pie == currentPie:
1523 | try:
1524 | paramGet.SetString("CurrentPie", text.encode('UTF-8'))
1525 | except TypeError:
1526 | paramGet.SetString("CurrentPie", text)
1527 | else:
1528 | pass
1529 | cBoxUpdate()
1530 |
1531 | buttonRenamePieMenu.clicked.connect(onButtonRenamePieMenu)
1532 |
1533 | buttonCopyPieMenu = QtGui.QToolButton()
1534 | buttonCopyPieMenu.setToolTip("Copy current pie menu")
1535 | buttonCopyPieMenu.setIcon(QtGui.QIcon(iconCopy))
1536 | buttonCopyPieMenu.setMinimumHeight(30)
1537 | buttonCopyPieMenu.setMinimumWidth(30)
1538 |
1539 |
1540 | def getCurrentMenuIndex(currentMenuName):
1541 |
1542 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1543 | indexList = paramIndexGet.GetString("IndexList")
1544 | indexList = splitIndexList(indexList)
1545 |
1546 | for i in indexList:
1547 | a = str(i)
1548 | indexName = paramIndexGet.GetString(a)
1549 | if indexName == currentMenuName:
1550 | return a;
1551 |
1552 | return "-1"
1553 |
1554 | def copyIndexParams(grpOrg, grpCopy):
1555 |
1556 | valButOrg = grpOrg.GetInt("Button")
1557 | valRadOrg = grpOrg.GetInt("Radius")
1558 | tbOrg = grpOrg.GetString("ToolList")
1559 |
1560 | grpCopy.SetInt("Button", valButOrg)
1561 | grpCopy.SetInt("Radius", valRadOrg)
1562 | grpCopy.SetString("ToolList", tbOrg)
1563 |
1564 | def copyContextParams(grpOrg, grpCopy):
1565 |
1566 | grpCntOrg = grpOrg.GetGroup("Context")
1567 | grpCntCopy = grpCopy.GetGroup("Context")
1568 |
1569 | enabledOrg = grpCntOrg.GetBool("Enabled")
1570 | vtxSgnOrg = grpCntOrg.GetString("VertexSign")
1571 | vtxValOrg = grpCntOrg.GetInt("VertexValue")
1572 | edgSgnOrg = grpCntOrg.GetString("EdgeSign")
1573 | edgValOrg = grpCntOrg.GetInt("EdgeValue")
1574 | fceSgnOrg = grpCntOrg.GetString("FaceSign")
1575 | fceValOrg = grpCntOrg.GetInt("FaceValue")
1576 | objSgnOrg = grpCntOrg.GetString("ObjectSign")
1577 | objValOrg = grpCntOrg.GetInt("ObjectValue")
1578 |
1579 | grpCntCopy.SetBool("Enabled", enabledOrg)
1580 | grpCntCopy.SetString("VertexSign", vtxSgnOrg)
1581 | grpCntCopy.SetInt("VertexValue", vtxValOrg)
1582 | grpCntCopy.SetString("EdgeSign", edgSgnOrg)
1583 | grpCntCopy.SetInt("EdgeValue", edgValOrg)
1584 | grpCntCopy.SetString("FaceSign", fceSgnOrg)
1585 | grpCntCopy.SetInt("FaceValue", fceValOrg)
1586 | grpCntCopy.SetString("ObjectSign", objSgnOrg)
1587 | grpCntCopy.SetInt("ObjectValue", objValOrg)
1588 |
1589 |
1590 | def onButtonCopyPieMenu():
1591 |
1592 | text, ok = inputTextDialog("Copy menu")
1593 | if not ok:
1594 | return
1595 |
1596 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1597 | indexList = paramIndexGet.GetString("IndexList")
1598 | indexList = splitIndexList(indexList)
1599 |
1600 | currentMenuName = cBox.currentText()
1601 | indexOrg = getCurrentMenuIndex(currentMenuName)
1602 |
1603 | pieList = []
1604 |
1605 | for i in indexList:
1606 | a = str(i)
1607 | pieList.append(paramIndexGet.GetString(a))
1608 |
1609 | if text.encode('UTF-8') in pieList:
1610 | pass
1611 | elif not text:
1612 | pass
1613 | else:
1614 | x = 1
1615 |
1616 | while x in indexList and x < 999:
1617 | x = x + 1
1618 | else:
1619 | indexCopy = x
1620 |
1621 | indexList.append(indexCopy)
1622 |
1623 | temp = []
1624 |
1625 | for i in indexList:
1626 | temp.append(str(i))
1627 |
1628 | indexList = temp
1629 |
1630 | paramIndexGet.SetString("IndexList", ".,.".join(indexList))
1631 |
1632 | indexCopy = str(indexCopy)
1633 | grpOrg = paramIndexGet.GetGroup(indexOrg)
1634 | grpCopy = paramIndexGet.GetGroup(indexCopy)
1635 | copyIndexParams(grpOrg, grpCopy)
1636 | copyContextParams(grpOrg, grpCopy)
1637 |
1638 | try:
1639 | paramIndexGet.SetString(indexCopy, text.encode('UTF-8'))
1640 | except TypeError:
1641 | paramIndexGet.SetString(indexCopy, text)
1642 |
1643 | cBoxUpdate()
1644 |
1645 | buttonCopyPieMenu.clicked.connect(onButtonCopyPieMenu)
1646 |
1647 | labelRadius = QtGui.QLabel("Pie size")
1648 | spinRadius = QtGui.QSpinBox()
1649 | spinRadius.setMaximum(9999)
1650 | spinRadius.setMinimumWidth(70)
1651 |
1652 |
1653 | def onSpinRadius():
1654 | group = getGroup()
1655 | value = spinRadius.value()
1656 | group.SetInt("Radius", value)
1657 |
1658 | spinRadius.valueChanged.connect(onSpinRadius)
1659 |
1660 | labelButton = QtGui.QLabel("Button size")
1661 | spinButton = QtGui.QSpinBox()
1662 | spinButton.setMaximum(999)
1663 | spinButton.setMinimumWidth(70)
1664 |
1665 |
1666 | def onSpinButton():
1667 | group = getGroup()
1668 | value = spinButton.value()
1669 | group.SetInt("Button", value)
1670 |
1671 | spinButton.valueChanged.connect(onSpinButton)
1672 |
1673 | toolListWidget = QtGui.QListWidget()
1674 | toolListWidget.setSortingEnabled(True)
1675 | toolListWidget.sortItems(QtCore.Qt.AscendingOrder)
1676 | toolListWidget.setHorizontalScrollBarPolicy(QtCore
1677 | .Qt.ScrollBarAlwaysOff)
1678 |
1679 |
1680 | def toolList():
1681 |
1682 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1683 | indexList = paramIndexGet.GetString("IndexList")
1684 |
1685 | text = cBox.currentText()
1686 |
1687 | actionMapAll = getGuiActionMapAll()
1688 |
1689 | toolListWidget.blockSignals(True)
1690 | toolListWidget.clear()
1691 |
1692 | for i in actionMapAll:
1693 | item = QtGui.QListWidgetItem(toolListWidget)
1694 | item.setText(actionMapAll[i].text().replace("&", ""))
1695 | item.setIcon(actionMapAll[i].icon())
1696 | item.setCheckState(QtCore.Qt.CheckState(0))
1697 | item.setData(QtCore.Qt.UserRole, actionMapAll[i].objectName())
1698 |
1699 | if indexList:
1700 | indexList = indexList.split(".,.")
1701 |
1702 | temp = []
1703 |
1704 | for i in indexList:
1705 | temp.append(int(i))
1706 |
1707 | indexList = temp
1708 | else:
1709 |
1710 | indexList = []
1711 |
1712 | toolListOn = None
1713 |
1714 | for i in indexList:
1715 | a = str(i)
1716 | try:
1717 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1718 | except AttributeError:
1719 | pie = paramIndexGet.GetString(a)
1720 | if pie == text:
1721 | group = paramIndexGet.GetGroup(a)
1722 | toolListOn = group.GetString("ToolList")
1723 | else:
1724 | pass
1725 |
1726 | if toolListOn:
1727 | toolListOn = toolListOn.split(".,.")
1728 | else:
1729 | toolListOn = []
1730 |
1731 | items = []
1732 | for index in range(toolListWidget.count()):
1733 | items.append(toolListWidget.item(index))
1734 |
1735 | for i in items:
1736 | if i.data(QtCore.Qt.UserRole) in toolListOn:
1737 | i.setCheckState(QtCore.Qt.CheckState(2))
1738 | else:
1739 | pass
1740 |
1741 | toolListWidget.blockSignals(False)
1742 |
1743 |
1744 | def onToolListWidget():
1745 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
1746 |
1747 | text = cBox.currentText()
1748 |
1749 | items = []
1750 | for index in range(toolListWidget.count()):
1751 | items.append(toolListWidget.item(index))
1752 |
1753 | checkListOn = []
1754 | checkListOff = []
1755 | for i in items:
1756 | if i.checkState():
1757 | checkListOn.append(i.data(QtCore.Qt.UserRole))
1758 | else:
1759 | checkListOff.append(i.data(QtCore.Qt.UserRole))
1760 |
1761 | indexList = paramIndexGet.GetString("IndexList")
1762 |
1763 | if indexList:
1764 | indexList = indexList.split(".,.")
1765 |
1766 | temp = []
1767 |
1768 | for i in indexList:
1769 | temp.append(int(i))
1770 |
1771 | indexList = temp
1772 | else:
1773 | indexList = []
1774 |
1775 | toolList = None
1776 |
1777 | for i in indexList:
1778 | a = str(i)
1779 | try:
1780 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1781 | except AttributeError:
1782 | pie = paramIndexGet.GetString(a)
1783 | if pie == text:
1784 | group = paramIndexGet.GetGroup(a)
1785 | toolList = group.GetString("ToolList")
1786 | else:
1787 | pass
1788 |
1789 | if toolList:
1790 | toolList = toolList.split(".,.")
1791 | else:
1792 | toolList = []
1793 |
1794 | for i in checkListOn:
1795 | if i not in toolList:
1796 | toolList.append(i)
1797 | else:
1798 | pass
1799 |
1800 | for i in checkListOff:
1801 | if i in toolList:
1802 | toolList.remove(i)
1803 | else:
1804 | pass
1805 |
1806 | for i in indexList:
1807 | a = str(i)
1808 | try:
1809 | pie = paramIndexGet.GetString(a).decode("UTF-8")
1810 | except AttributeError:
1811 | pie = paramIndexGet.GetString(a)
1812 | if pie == text:
1813 | group = paramIndexGet.GetGroup(a)
1814 | toolList = group.SetString("ToolList", ".,.".join(toolList))
1815 | else:
1816 | pass
1817 |
1818 | buttonList()
1819 |
1820 | toolListWidget.itemChanged.connect(onToolListWidget)
1821 |
1822 |
1823 | def buttonList2ToolList(buttonListWidget):
1824 |
1825 | items = []
1826 | for index in range(buttonListWidget.count()):
1827 | items.append(buttonListWidget.item(index))
1828 |
1829 | toolData = []
1830 | for i in items:
1831 | toolData.append(i.data(QtCore.Qt.UserRole))
1832 |
1833 | group = getGroup()
1834 | group.SetString("ToolList", ".,.".join(toolData))
1835 |
1836 |
1837 | buttonUp = QtGui.QToolButton()
1838 | buttonUp.setIcon(QtGui.QIcon(iconUp))
1839 | buttonUp.setToolTip("Move selected command up")
1840 | buttonUp.setMinimumHeight(30)
1841 | buttonUp.setMinimumWidth(30)
1842 |
1843 |
1844 | def onButtonUp():
1845 | currentIndex = buttonListWidget.currentRow()
1846 |
1847 | if currentIndex != 0:
1848 | currentItem = buttonListWidget.takeItem(currentIndex)
1849 | buttonListWidget.insertItem(currentIndex - 1, currentItem)
1850 | buttonListWidget.setCurrentRow(currentIndex - 1)
1851 | buttonList2ToolList(buttonListWidget)
1852 |
1853 | buttonUp.clicked.connect(onButtonUp)
1854 |
1855 | buttonDown = QtGui.QToolButton()
1856 | buttonDown.setIcon(QtGui.QIcon(iconDown))
1857 | buttonDown.setToolTip("Move selected command down")
1858 | buttonDown.setMinimumHeight(30)
1859 | buttonDown.setMinimumWidth(30)
1860 |
1861 |
1862 | def onButtonDown():
1863 | currentIndex = buttonListWidget.currentRow()
1864 |
1865 | if currentIndex != buttonListWidget.count() - 1 and currentIndex != -1:
1866 | currentItem = buttonListWidget.takeItem(currentIndex)
1867 | buttonListWidget.insertItem(currentIndex + 1, currentItem)
1868 | buttonListWidget.setCurrentRow(currentIndex + 1)
1869 | buttonList2ToolList(buttonListWidget)
1870 |
1871 | buttonDown.clicked.connect(onButtonDown)
1872 |
1873 | buttonRemoveCommand = QtGui.QPushButton()
1874 | buttonRemoveCommand.setIcon(QtGui.QIcon(iconRemoveCommand))
1875 | buttonRemoveCommand.setToolTip("Remove selected command")
1876 | buttonRemoveCommand.setMinimumHeight(30)
1877 | buttonRemoveCommand.setMinimumWidth(30)
1878 |
1879 |
1880 | def onButtonRemoveCommand():
1881 |
1882 | currentIndex = buttonListWidget.currentRow()
1883 | buttonListWidget.takeItem(currentIndex)
1884 |
1885 | if currentIndex != 0:
1886 | buttonListWidget.setCurrentRow(currentIndex - 1)
1887 | buttonListWidget.setFocus()
1888 | buttonList2ToolList(buttonListWidget)
1889 | toolList()
1890 |
1891 | buttonRemoveCommand.clicked.connect(onButtonRemoveCommand)
1892 |
1893 | vertexItem = QtGui.QTableWidgetItem()
1894 | vertexItem.setText("Vertex")
1895 | vertexItem.setToolTip("Set desired operator and vertex number")
1896 | vertexItem.setFlags(QtCore.Qt.ItemIsEnabled)
1897 |
1898 | edgeItem = QtGui.QTableWidgetItem()
1899 | edgeItem.setText("Edge")
1900 | edgeItem.setToolTip("Set desired operator and edge number")
1901 | edgeItem.setFlags(QtCore.Qt.ItemIsEnabled)
1902 |
1903 | faceItem = QtGui.QTableWidgetItem()
1904 | faceItem.setText("Face")
1905 | faceItem.setToolTip("Set desired operator and face number")
1906 | faceItem.setFlags(QtCore.Qt.ItemIsEnabled)
1907 |
1908 | objectItem = QtGui.QTableWidgetItem()
1909 | objectItem.setText("Object")
1910 | objectItem.setToolTip("Set desired operator and object number")
1911 | objectItem.setFlags(QtCore.Qt.ItemIsEnabled)
1912 |
1913 |
1914 | def comboBox(TopoType):
1915 | signList = ["<", "<=", "==", "!=", ">", ">="]
1916 |
1917 | model = QtGui.QStandardItemModel()
1918 |
1919 | for i in signList:
1920 | item = QtGui.QStandardItem()
1921 | item.setText(i)
1922 | item.setData(TopoType, QtCore.Qt.UserRole)
1923 |
1924 | model.setItem(signList.index(i), 0, item)
1925 |
1926 | comboBoxSign = QtGui.QComboBox()
1927 | comboBoxSign.setModel(model)
1928 | comboBoxSign.setStyleSheet(styleCombo)
1929 |
1930 | def onCurrentIndexChanged():
1931 | group = getGroup()
1932 |
1933 | groupContext = group.GetGroup("Context")
1934 | text = comboBoxSign.currentText()
1935 | topo = comboBoxSign.itemData(comboBoxSign.currentIndex(),
1936 | QtCore.Qt.UserRole)
1937 | groupContext.SetString(topo, text)
1938 |
1939 | contextList()
1940 |
1941 | comboBoxSign.currentIndexChanged.connect(onCurrentIndexChanged)
1942 |
1943 | return comboBoxSign
1944 |
1945 | vertexComboBox = comboBox("VertexSign")
1946 | edgeComboBox = comboBox("EdgeSign")
1947 | faceComboBox = comboBox("FaceSign")
1948 | objectComboBox = comboBox("ObjectSign")
1949 |
1950 |
1951 | def spinBox(TopoValue):
1952 |
1953 | spinBox = QtGui.QSpinBox()
1954 | spinBox.setFrame(False)
1955 |
1956 | def onSpinBox():
1957 | group = getGroup()
1958 |
1959 | groupContext = group.GetGroup("Context")
1960 | value = spinBox.value()
1961 | groupContext.SetInt(TopoValue, value)
1962 |
1963 | contextList()
1964 |
1965 | spinBox.valueChanged.connect(onSpinBox)
1966 |
1967 | return spinBox
1968 |
1969 | vertexSpin = spinBox("VertexValue")
1970 | edgeSpin = spinBox("EdgeValue")
1971 | faceSpin = spinBox("FaceValue")
1972 | objectSpin = spinBox("ObjectValue")
1973 |
1974 | labelContext = QtGui.QLabel("Enable")
1975 | checkContext = QtGui.QCheckBox()
1976 |
1977 |
1978 | def setCheckContext():
1979 |
1980 | group = getGroup()
1981 | groupContext = group.GetGroup("Context")
1982 |
1983 | if groupContext.GetBool("Enabled"):
1984 | checkContext.setChecked(True)
1985 | contextTable.setEnabled(True)
1986 | resetButton.setEnabled(True)
1987 | else:
1988 | checkContext.setChecked(False)
1989 | contextTable.setEnabled(False)
1990 | resetButton.setEnabled(False)
1991 |
1992 | contextList()
1993 |
1994 |
1995 | def onCheckContext():
1996 |
1997 | setDefaults()
1998 |
1999 | group = getGroup()
2000 | groupContext = group.GetGroup("Context")
2001 |
2002 | if checkContext.isChecked():
2003 | contextTable.setEnabled(True)
2004 | resetButton.setEnabled(True)
2005 |
2006 | groupContext.SetBool("Enabled", 1)
2007 |
2008 | else:
2009 | contextTable.setEnabled(False)
2010 | resetButton.setEnabled(False)
2011 |
2012 | groupContext.SetBool("Enabled", 0)
2013 |
2014 | contextList()
2015 |
2016 | checkContext.stateChanged.connect(onCheckContext)
2017 |
2018 | contextTable = QtGui.QTableWidget(4, 3)
2019 | contextTable.setMaximumHeight(120)
2020 | contextTable.setFrameStyle(QtGui.QFrame.NoFrame)
2021 | contextTable.verticalHeader().setVisible(False)
2022 | contextTable.horizontalHeader().setVisible(False)
2023 | try:
2024 | contextTable.verticalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
2025 | contextTable.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
2026 | except AttributeError:
2027 | contextTable.verticalHeader().setSectionResizeMode(QtGui.QHeaderView.Stretch)
2028 | contextTable.horizontalHeader().setSectionResizeMode(QtGui.QHeaderView.Stretch)
2029 |
2030 | contextTable.setItem(0, 0, vertexItem)
2031 | contextTable.setCellWidget(0, 1, vertexComboBox)
2032 | contextTable.setCellWidget(0, 2, vertexSpin)
2033 |
2034 | contextTable.setItem(1, 0, edgeItem)
2035 | contextTable.setCellWidget(1, 1, edgeComboBox)
2036 | contextTable.setCellWidget(1, 2, edgeSpin)
2037 |
2038 | contextTable.setItem(2, 0, faceItem)
2039 | contextTable.setCellWidget(2, 1, faceComboBox)
2040 | contextTable.setCellWidget(2, 2, faceSpin)
2041 |
2042 | contextTable.setItem(3, 0, objectItem)
2043 | contextTable.setCellWidget(3, 1, objectComboBox)
2044 | contextTable.setCellWidget(3, 2, objectSpin)
2045 |
2046 | resetButton = QtGui.QToolButton()
2047 | resetButton.setMinimumHeight(30)
2048 | resetButton.setMinimumWidth(30)
2049 | resetButton.setText(u'\u27F3')
2050 |
2051 | resetButton.setEnabled(False)
2052 |
2053 |
2054 | def onResetButton():
2055 |
2056 | group = getGroup()
2057 | group.RemGroup("Context")
2058 | setDefaults()
2059 | setCheckContext()
2060 |
2061 | resetButton.clicked.connect(onResetButton)
2062 |
2063 |
2064 | def setDefaults():
2065 | group = getGroup()
2066 | groupContext = group.GetGroup("Context")
2067 |
2068 | vertexSign = groupContext.GetString("VertexSign")
2069 |
2070 | if vertexSign in sign:
2071 | pass
2072 | else:
2073 | groupContext.SetString("VertexSign", "==")
2074 | vertexSign = "=="
2075 |
2076 | for i in range(vertexComboBox.count()):
2077 | if vertexComboBox.itemText(i) == vertexSign:
2078 | vertexComboBox.setCurrentIndex(i)
2079 | else:
2080 | pass
2081 |
2082 | vertexValue = groupContext.GetInt("VertexValue")
2083 |
2084 | if vertexValue:
2085 | pass
2086 | else:
2087 | a = groupContext.GetInt("VertexValue", True)
2088 | b = groupContext.GetInt("VertexValue", False)
2089 |
2090 | if a == b:
2091 | groupContext.SetInt("VertexValue", 0)
2092 | vertexValue = 0
2093 | else:
2094 | groupContext.SetInt("VertexValue", 10)
2095 | vertexValue = 10
2096 |
2097 | vertexSpin.setValue(vertexValue)
2098 |
2099 | edgeSign = groupContext.GetString("EdgeSign")
2100 |
2101 | if edgeSign in sign:
2102 | pass
2103 | else:
2104 | groupContext.SetString("EdgeSign", "==")
2105 | edgeSign = "=="
2106 |
2107 | for i in range(edgeComboBox.count()):
2108 | if edgeComboBox.itemText(i) == edgeSign:
2109 | edgeComboBox.setCurrentIndex(i)
2110 | else:
2111 | pass
2112 |
2113 | edgeValue = groupContext.GetInt("EdgeValue")
2114 |
2115 | if edgeValue:
2116 | pass
2117 | else:
2118 | a = groupContext.GetInt("EdgeValue", True)
2119 | b = groupContext.GetInt("EdgeValue", False)
2120 |
2121 | if a == b:
2122 | groupContext.SetInt("EdgeValue", 0)
2123 | edgeValue = 0
2124 | else:
2125 | groupContext.SetInt("EdgeValue", 10)
2126 | edgeValue = 10
2127 |
2128 | edgeSpin.setValue(edgeValue)
2129 |
2130 | faceSign = groupContext.GetString("FaceSign")
2131 |
2132 | if faceSign in sign:
2133 | pass
2134 | else:
2135 | groupContext.SetString("FaceSign", "==")
2136 | faceSign = "=="
2137 |
2138 | for i in range(faceComboBox.count()):
2139 | if faceComboBox.itemText(i) == faceSign:
2140 | faceComboBox.setCurrentIndex(i)
2141 | else:
2142 | pass
2143 |
2144 | faceValue = groupContext.GetInt("FaceValue")
2145 |
2146 | if faceValue:
2147 | pass
2148 | else:
2149 | a = groupContext.GetInt("FaceValue", True)
2150 | b = groupContext.GetInt("FaceValue", False)
2151 |
2152 | if a == b:
2153 | groupContext.SetInt("FaceValue", 0)
2154 | faceValue = 0
2155 | else:
2156 | groupContext.SetInt("FaceValue", 10)
2157 | faceValue = 10
2158 |
2159 | faceSpin.setValue(faceValue)
2160 |
2161 | objectSign = groupContext.GetString("ObjectSign")
2162 |
2163 | if objectSign in sign:
2164 | pass
2165 | else:
2166 | groupContext.SetString("ObjectSign", "==")
2167 | objectSign = "=="
2168 |
2169 | for i in range(objectComboBox.count()):
2170 | if objectComboBox.itemText(i) == objectSign:
2171 | objectComboBox.setCurrentIndex(i)
2172 | else:
2173 | pass
2174 |
2175 | objectValue = groupContext.GetInt("ObjectValue")
2176 |
2177 | if objectValue:
2178 | pass
2179 | else:
2180 | a = groupContext.GetInt("ObjectValue", True)
2181 | b = groupContext.GetInt("ObjectValue", False)
2182 |
2183 | if a == b:
2184 | groupContext.SetInt("ObjectValue", 0)
2185 | objectValue = 0
2186 | else:
2187 | groupContext.SetInt("ObjectValue", 10)
2188 | objectValue = 10
2189 |
2190 | objectSpin.setValue(objectValue)
2191 |
2192 | valueRadius = group.GetInt("Radius")
2193 |
2194 | if valueRadius:
2195 | pass
2196 | else:
2197 | valueRadius = 100
2198 | group.SetInt("Radius", valueRadius)
2199 |
2200 | spinRadius.setValue(valueRadius)
2201 |
2202 | valueButton = group.GetInt("Button")
2203 |
2204 | if valueButton:
2205 | pass
2206 | else:
2207 | valueButton = 32
2208 | group.SetInt("Button", valueButton)
2209 |
2210 | spinButton.setValue(valueButton)
2211 |
2212 | contextList()
2213 |
2214 |
2215 | def setDefaultPie(restore=False):
2216 | paramGet = App.ParamGet("User parameter:BaseApp/PieMenu")
2217 | paramIndexGet = App.ParamGet("User parameter:BaseApp/PieMenu/Index")
2218 | indexList = paramIndexGet.GetString("IndexList")
2219 |
2220 | defaultTools = ["Std_ViewTop",
2221 | "Std_New",
2222 | "Std_ViewRight",
2223 | "Std_BoxSelection",
2224 | "Std_ViewBottom",
2225 | "Std_ViewIsometric",
2226 | "Std_ViewLeft",
2227 | "Std_ViewScreenShot"]
2228 |
2229 | if indexList:
2230 | indexList = indexList.split(".,.")
2231 |
2232 | temp = []
2233 |
2234 | for i in indexList:
2235 | temp.append(int(i))
2236 |
2237 | indexList = temp
2238 | else:
2239 | indexList = []
2240 |
2241 | if 0 in indexList:
2242 | if restore:
2243 | group = paramIndexGet.GetGroup("0")
2244 | group.SetString("ToolList", ".,.".join(defaultTools))
2245 | else:
2246 | pass
2247 | else:
2248 | indexList.append(0)
2249 |
2250 | temp = []
2251 |
2252 | for i in indexList:
2253 | temp.append(str(i))
2254 |
2255 | indexList = temp
2256 |
2257 | paramIndexGet.SetString("0", "Default")
2258 | paramIndexGet.SetString("IndexList", ".,.".join(indexList))
2259 |
2260 | group = paramIndexGet.GetGroup("0")
2261 | group.SetString("ToolList", ".,.".join(defaultTools))
2262 |
2263 | paramGet.SetBool("ToolBar", False)
2264 | paramGet.RemString("ToolBar")
2265 | paramGet.SetString("CurrentPie", "Default")
2266 |
2267 | group = getGroup(mode=1)
2268 |
2269 | group.SetInt("Radius", 100)
2270 | group.SetInt("Button", 32)
2271 |
2272 | def onControl():
2273 |
2274 | global pieMenuDialog
2275 |
2276 | for i in mw.findChildren(QtGui.QDialog):
2277 | if i.objectName() == "PieMenuPreferences":
2278 | i.deleteLater()
2279 | else:
2280 | pass
2281 |
2282 | tabs = QtGui.QTabWidget()
2283 |
2284 | pieMenuTab = QtGui.QWidget()
2285 | pieMenuTabLayout = QtGui.QVBoxLayout()
2286 | pieMenuTab.setLayout(pieMenuTabLayout)
2287 |
2288 | layoutAddRemove = QtGui.QHBoxLayout()
2289 | layoutAddRemove.addWidget(cBox)
2290 | layoutAddRemove.addWidget(buttonAddPieMenu)
2291 | layoutAddRemove.addWidget(buttonRemovePieMenu)
2292 | layoutAddRemove.addWidget(buttonRenamePieMenu)
2293 | layoutAddRemove.addWidget(buttonCopyPieMenu)
2294 |
2295 | layoutRadius = QtGui.QHBoxLayout()
2296 | layoutRadius.addWidget(labelRadius)
2297 | layoutRadius.addStretch(1)
2298 | layoutRadius.addWidget(spinRadius)
2299 |
2300 | layoutButton = QtGui.QHBoxLayout()
2301 | layoutButton.addWidget(labelButton)
2302 | layoutButton.addStretch(1)
2303 | layoutButton.addWidget(spinButton)
2304 |
2305 | pieMenuTabLayout.insertLayout(0, layoutAddRemove)
2306 | pieMenuTabLayout.insertSpacing(1, 24)
2307 | pieMenuTabLayout.insertLayout(2, layoutRadius)
2308 | pieMenuTabLayout.insertLayout(3, layoutButton)
2309 | pieMenuTabLayout.addStretch(0)
2310 |
2311 | contextTab = QtGui.QWidget()
2312 | contextTabLayout = QtGui.QVBoxLayout()
2313 | contextTab.setLayout(contextTabLayout)
2314 |
2315 | layoutCheckContext = QtGui.QHBoxLayout()
2316 | layoutCheckContext.addWidget(labelContext)
2317 | layoutCheckContext.addStretch(1)
2318 | layoutCheckContext.addWidget(checkContext)
2319 |
2320 | resetLayout = QtGui.QHBoxLayout()
2321 | resetLayout.addStretch(1)
2322 | resetLayout.addWidget(resetButton)
2323 |
2324 | contextTabLayout.insertLayout(0, layoutCheckContext)
2325 | contextTabLayout.addWidget(contextTable)
2326 | contextTabLayout.insertLayout(2, resetLayout)
2327 | contextTabLayout.addStretch(1)
2328 |
2329 | tabs.addTab(pieMenuTab, "PieMenu")
2330 | tabs.addTab(toolListWidget, "Tools")
2331 | tabs.addTab(contextTab, "Context")
2332 |
2333 | pieButtons = QtGui.QWidget()
2334 | pieButtonsLayout = QtGui.QVBoxLayout()
2335 | pieButtons.setLayout(pieButtonsLayout)
2336 | pieButtonsLayout.setContentsMargins(0, 0, 0, 0)
2337 | pieButtonsLayout.addWidget(buttonListWidget)
2338 |
2339 | buttonsLayout = QtGui.QHBoxLayout()
2340 | buttonsLayout.addStretch(1)
2341 | buttonsLayout.addWidget(buttonRemoveCommand)
2342 | buttonsLayout.addWidget(buttonDown)
2343 | buttonsLayout.addWidget(buttonUp)
2344 |
2345 | pieButtonsLayout.insertLayout(1, buttonsLayout)
2346 |
2347 | vSplitter = QtGui.QSplitter()
2348 | vSplitter.insertWidget(0, pieButtons)
2349 | vSplitter.insertWidget(0, tabs)
2350 |
2351 | preferencesWidget = QtGui.QWidget()
2352 | preferencesLayout = QtGui.QHBoxLayout()
2353 | preferencesLayout.setContentsMargins(0, 0, 0, 0)
2354 | preferencesWidget.setLayout(preferencesLayout)
2355 | preferencesLayout.addWidget(vSplitter)
2356 |
2357 | pieMenuDialog = QtGui.QDialog(mw)
2358 | pieMenuDialog.resize(800, 450)
2359 | pieMenuDialog.setObjectName("PieMenuPreferences")
2360 | pieMenuDialog.setWindowTitle("PieMenu " + PIE_MENU_VERSION)
2361 | pieMenuDialogLayout = QtGui.QVBoxLayout()
2362 | pieMenuDialog.setLayout(pieMenuDialogLayout)
2363 | pieMenuDialog.show()
2364 |
2365 | pieMenuDialogLayout.addWidget(preferencesWidget)
2366 |
2367 | cBoxUpdate()
2368 |
2369 |
2370 | def addAccessoriesMenu():
2371 |
2372 | if mw.property("eventLoop"):
2373 |
2374 | startAM = False
2375 | try:
2376 | mw.mainWindowClosed
2377 | mw.workbenchActivated
2378 | startAM = True
2379 | except AttributeError:
2380 | pass
2381 | if startAM:
2382 | t.stop()
2383 | t.deleteLater()
2384 | accessoriesMenu()
2385 |
2386 |
2387 | mw = Gui.getMainWindow()
2388 | start = True
2389 |
2390 | for action in mw.findChildren(QtGui.QAction):
2391 | if action.objectName() == "PieMenuShortCut":
2392 | start = False
2393 | else:
2394 | pass
2395 |
2396 | if start:
2397 |
2398 | remObsoleteParams()
2399 | compositingManager = True
2400 | if QtCore.qVersion() < "5":
2401 | windowShadow = False
2402 | else:
2403 | windowShadow = True
2404 |
2405 | if platform.system() == "Linux":
2406 | try:
2407 | if QtGui.QX11Info.isCompositingManagerRunning():
2408 | windowShadow = True
2409 | else:
2410 | compositingManager = False
2411 | except AttributeError:
2412 | windowShadow = True
2413 | else:
2414 | pass
2415 |
2416 | if platform.system() == "Windows":
2417 | windowShadow = True
2418 | else:
2419 | pass
2420 |
2421 | contextAll = {}
2422 | contextList()
2423 | selObserver = SelObserver()
2424 | addObserver()
2425 |
2426 | PieMenuInstance = PieMenu()
2427 |
2428 | actionKey = QtGui.QAction(mw)
2429 | actionKey.setText("Invoke pie menu")
2430 | actionKey.setObjectName("PieMenuShortCut")
2431 | actionKey.setShortcut(QtGui.QKeySequence("TAB"))
2432 | actionKey.triggered.connect(PieMenuInstance.showAtMouse)
2433 | mw.addAction(actionKey)
2434 |
2435 | # let the addition of the accessoriesMenu wait until FC is ready for it
2436 | t = QtCore.QTimer()
2437 | t.timeout.connect(addAccessoriesMenu)
2438 | t.start(500)
2439 |
2440 | else:
2441 | pass
2442 |
2443 | pieMenuStart()
--------------------------------------------------------------------------------