├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── examples
├── Makefile
├── container.cpp
├── rootcontainer.cpp
└── widgets.cpp
├── images
├── dock_example.gif
├── ogv2gif.sh
└── tooltip_example.gif
├── imgui
├── Makefile
├── imconfig.h
├── imgui.cpp
├── imgui.h
├── imgui_demo.cpp
├── imgui_draw.cpp
├── imgui_impl_glfw.cpp
├── imgui_impl_glfw.h
├── imgui_internal.h
├── stb_rect_pack.h
├── stb_textedit.h
└── stb_truetype.h
├── imgui_dock.cpp
├── imgui_dock.h
├── imgui_widgets.cpp
└── imgui_widgets.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .depend
2 | *~
3 | *.o
4 | examples/container
5 | examples/rootcontainer
6 | examples/widgets
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | RM=rm -f
3 | CXXFLAGS=-I./ -I./imgui/ $(shell pkg-config --cflags glfw3 glu gl) -Wall -Wformat -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++11 -w -g
4 | CFLAGS = $(CXXFLAGS)
5 | LDFLAGS=-g $(shell pkg-config --libs glfw3 glu gl)
6 |
7 | SRCS=imgui_dock.cpp imgui_widgets.cpp
8 | OBJS=$(subst .cpp,.o,$(SRCS))
9 |
10 | all: .depend $(OBJS)
11 | @true
12 |
13 | .depend: $(SRCS)
14 | $(RM) ./.depend
15 | $(CXX) $(CXXFLAGS) -MM $^>>./.depend;
16 |
17 | clean:
18 | $(RM) $(OBJS)
19 |
20 | distclean: clean
21 | $(RM) *~ .depend
22 |
23 | include .depend
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImGui Goodies
2 |
3 | This is a collection of widgets and utilities for the
4 | [immediate mode GUI (imgui)](https://github.com/ocornut/imgui) that I
5 | am developing for the critic2 GUI. Currently, the contents of this
6 | repo are:
7 |
8 | * `imgui_widget.cpp`: a collection of small independent widgets,
9 | including:
10 |
11 | + `SlidingBar`: a bar widget that slides when it is grabbed with the
12 | mouse.
13 |
14 | + `ButtonWithX`: a button with an X at the end. Useful for tabs.
15 |
16 | + `ResizeGripOther`: a resize grip that resizes a window other than
17 | the one on which it is drawn.
18 |
19 | + `LiftGrip`: a grip on the bottom left part of the window rendered in
20 | a different color. Responds to grabbing.
21 |
22 | + `AttachTooltip`: a function that provides delayed
23 | tooltips. Tooltips are shown if: i) the mouse hovers over the
24 | element for longer than a certain time, passed as argument to the
25 | function, ii) the mouse goes from one tooltip element to another,
26 | and the tooltip is being shown, or iii) the mouse hovers a tooltip
27 | element for longer than t seconds and less than t seconds have
28 | elapsed between the time the last tooltip was shown and the current
29 | item started being hovered. See example below.
30 |
31 | * `imgui_dock.cpp`: a window docking system. There are three types of
32 | windows:
33 |
34 | + Docks (`BeginDock()`/`EndDock()`): like normal windows, except
35 | they can be docked to the other two window types.
36 |
37 | + Containers (`Container()`): a window to which docks can be
38 | attached as tabs. It has a behavior similar to a browser window.
39 |
40 | + Root containers (`RootContainer()`): a window to which both
41 | containers and docks can be attached. It splits into regions for
42 | the different attached windows depending on where they are
43 | dropped.
44 |
45 | Most of the functionality of normal ImGui windows is
46 | preserved. `imgui_dock.cpp` uses the widgets in `imgui_widget.cpp`
47 | but is otherwise self-contained.
48 |
49 | Some examples are given in the `examples` subdirectory. Use the
50 | `compile.sh` script to build the whole directory tree.
51 |
52 | ## Examples
53 |
54 | Docks, containers, and root containers:
55 |
56 | 
57 |
58 | Delayed tooltips:
59 |
60 | 
61 |
62 |
--------------------------------------------------------------------------------
/examples/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | RM=rm -f
3 | CXXFLAGS=-I./ -I../ -I../imgui/ $(shell pkg-config --cflags glfw3 glu gl) -Wall -Wformat -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++11 -w -g
4 | CFLAGS = $(CXXFLAGS)
5 | LDFLAGS=-g -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++11 $(shell pkg-config --libs glfw3 glu gl)
6 |
7 | OBJS=../imgui/imgui.o ../imgui/imgui_draw.o ../imgui/imgui_demo.o ../imgui/imgui_impl_glfw.o \
8 | ../imgui_dock.o ../imgui_widgets.o
9 |
10 | .cpp.o:
11 | $(CXX) $(CXXFLAGS) -c -o $@ $<
12 |
13 | all: widgets container rootcontainer
14 | @true
15 |
16 | widgets: widgets.o $(OBJS)
17 | $(CXX) $(LDFLAGS) -o $@ $(LDFLAGS) $@.o $(OBJS)
18 |
19 | container: container.o $(OBJS)
20 | $(CXX) $(LDFLAGS) -o $@ $(LDFLAGS) $@.o $(OBJS)
21 |
22 | rootcontainer: rootcontainer.o $(OBJS)
23 | $(CXX) $(LDFLAGS) -o $@ $(LDFLAGS) $@.o $(OBJS)
24 |
25 | clean:
26 | $(RM) *.o $(BINS)
27 |
28 |
--------------------------------------------------------------------------------
/examples/container.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017 Alberto Otero de la Roza
3 | .
4 |
5 | imgui-goodies is free software: you can redistribute it and/or
6 | modify it under the terms of the GNU General Public License as
7 | published by the Free Software Foundation, either version 3 of the
8 | License, or (at your option) any later version.
9 |
10 | imgui-goodies is distributed in the hope that it will be useful, but
11 | WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | using namespace std;
31 | using namespace ImGui;
32 |
33 | static void error_callback(int error, const char* description){
34 | fprintf(stderr, "Error %d: %s\n", error, description);
35 | }
36 |
37 | int main(int argc, char *argv[]){
38 | // Initialize
39 | glfwSetErrorCallback(error_callback);
40 | if (!glfwInit()) exit(EXIT_FAILURE);
41 |
42 | // Set up window
43 | GLFWwindow* rootwin = glfwCreateWindow(1280, 720, "gcritic2", nullptr, nullptr);
44 | assert(rootwin!=nullptr);
45 | glfwMakeContextCurrent(rootwin);
46 |
47 | // Setup ImGui binding
48 | ImGui_ImplGlfwGL2_Init(rootwin, true);
49 |
50 | // GUI settings
51 | ImGuiIO& io = GetIO();
52 | io.IniFilename = nullptr;
53 |
54 | // Main loop
55 | while (!glfwWindowShouldClose(rootwin)){
56 | // New frame
57 | glfwPollEvents();
58 | ImGui_ImplGlfwGL2_NewFrame();
59 | ImGuiContext *g = GetCurrentContext();
60 | static bool first = true;
61 |
62 | // Main menu bar
63 | if (BeginMainMenuBar()){
64 | if (BeginMenu("File")){
65 | if (MenuItem("Quit","Ctrl+Q"))
66 | glfwSetWindowShouldClose(rootwin, GLFW_TRUE);
67 | EndMenu();
68 | }
69 | SameLine(0, GetWindowSize().x-250.);
70 | Text("%.3f ms/frame (%.1f FPS)", 1000.0f / GetIO().Framerate, GetIO().Framerate);
71 | }
72 | EndMainMenuBar();
73 |
74 | static bool pcont = true;
75 | ImGui::SetNextWindowPos(ImVec2(270,20),ImGuiSetCond_FirstUseEver);
76 | ImGui::SetNextWindowSize(ImVec2(300,300),ImGuiSetCond_FirstUseEver);
77 | Dock *dcont1 = nullptr;
78 | if (pcont)
79 | dcont1 = ImGui::Container("Floating Container",&pcont);
80 |
81 | ImGui::SetNextWindowPos(ImVec2(270,370),ImGuiSetCond_FirstUseEver);
82 | ImGui::SetNextWindowSize(ImVec2(300,300),ImGuiSetCond_FirstUseEver);
83 | Dock *dcont2 = ImGui::Container("Fixed Container",nullptr,ImGuiWindowFlags_NoResize|
84 | ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoBringToFrontOnFocus);
85 |
86 | // Some docks unattached on the side
87 | static bool popen[10] = {true,true,true,true,true,true,true,true,true,true};
88 | for (int i=0;i<10;i++){
89 | if (popen[i]){
90 | SetNextWindowPos(ImVec2(20.f,40.f),ImGuiSetCond_FirstUseEver);
91 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
92 | char tmp[16];
93 | sprintf(tmp,"Dock #%d",i);
94 | if (BeginDock(tmp,&(popen[i]))){
95 | Text("Hello, world!");
96 | if (Button("Click me!")){
97 | printf("Clicked in dock %d\n",i);
98 | }
99 | }
100 | EndDock();
101 | }
102 | }
103 |
104 | // Some docks attached to a container
105 | static Dock *pwhich[5] = {dcont1,dcont2,dcont1,dcont2,dcont1};
106 | static bool popen2[3] = {true,true,true};
107 | for (int i=0;i<3;i++){
108 | if (popen2[i]){
109 | char tmp[16];
110 | sprintf(tmp,"Dck #%d",i);
111 | if (BeginDock(tmp,&(popen2[i]),0,0,pwhich[i])){
112 | Text("Hello, world!");
113 | if (Button("Click me!")){
114 | printf("Clicked in dock %d\n",i);
115 | }
116 | }
117 | Dock *dtmp = GetCurrentDock();
118 | EndDock();
119 | if (first)
120 | dtmp->setDetachedDockSize(100.f, 100.f);
121 | }
122 | }
123 | for (int i=3;i<5;i++){
124 | char tmp[16];
125 | sprintf(tmp,"Dck #%d",i);
126 | if (BeginDock(tmp,nullptr,0,0,pwhich[i])){
127 | Text("You can not close me.");
128 | if (Button("Click me!")){
129 | printf("Clicked in dock %d\n",i);
130 | }
131 | }
132 | Dock *dtmp = GetCurrentDock();
133 | EndDock();
134 | if (first)
135 | dtmp->setDetachedDockSize(100.f, 100.f);
136 | }
137 |
138 | // Draw the current scene
139 | int w, h;
140 | glfwGetFramebufferSize(rootwin,&w,&h);
141 | glViewport(0,0,w,h);
142 | glClearColor(1.0f,0.8f,0.5f,0.0f);
143 | glClear(GL_COLOR_BUFFER_BIT);
144 |
145 | // Render and swap
146 | Render();
147 | glfwSwapBuffers(rootwin);
148 | first = false;
149 | }
150 |
151 | // Cleanup
152 | ShutdownDock();
153 | ImGui_ImplGlfwGL2_Shutdown();
154 | glfwTerminate();
155 |
156 | return 0;
157 | }
158 |
159 |
--------------------------------------------------------------------------------
/examples/rootcontainer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017 Alberto Otero de la Roza
3 | .
4 |
5 | imgui-goodies is free software: you can redistribute it and/or
6 | modify it under the terms of the GNU General Public License as
7 | published by the Free Software Foundation, either version 3 of the
8 | License, or (at your option) any later version.
9 |
10 | imgui-goodies is distributed in the hope that it will be useful, but
11 | WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | using namespace std;
31 | using namespace ImGui;
32 |
33 | static void error_callback(int error, const char* description){
34 | fprintf(stderr, "Error %d: %s\n", error, description);
35 | }
36 |
37 | int main(int argc, char *argv[]){
38 | // Initialize
39 | glfwSetErrorCallback(error_callback);
40 | if (!glfwInit()) exit(EXIT_FAILURE);
41 |
42 | // Set up window
43 | GLFWwindow* rootwin = glfwCreateWindow(1280, 720, "gcritic2", nullptr, nullptr);
44 | assert(rootwin!=nullptr);
45 | glfwMakeContextCurrent(rootwin);
46 |
47 | // Setup ImGui binding
48 | ImGui_ImplGlfwGL2_Init(rootwin, true);
49 |
50 | // GUI settings
51 | ImGuiIO& io = GetIO();
52 | io.IniFilename = nullptr;
53 |
54 | // Main loop
55 | while (!glfwWindowShouldClose(rootwin)){
56 | // New frame
57 | glfwPollEvents();
58 | ImGui_ImplGlfwGL2_NewFrame();
59 | ImGuiContext *g = GetCurrentContext();
60 | static bool first = true;
61 |
62 | // Main menu bar
63 | if (BeginMainMenuBar()){
64 | if (BeginMenu("File")){
65 | if (MenuItem("Quit","Ctrl+Q"))
66 | glfwSetWindowShouldClose(rootwin, GLFW_TRUE);
67 | EndMenu();
68 | }
69 | SameLine(0, GetWindowSize().x-250.);
70 | Text("%.3f ms/frame (%.1f FPS)", 1000.0f / GetIO().Framerate, GetIO().Framerate);
71 | }
72 | EndMainMenuBar();
73 |
74 | // Root container
75 | static bool proot = true;
76 | Dock *droot = nullptr;
77 | ImGui::SetNextWindowPos(ImVec2(590,70),ImGuiSetCond_FirstUseEver);
78 | ImGui::SetNextWindowSize(ImVec2(400,400),ImGuiSetCond_FirstUseEver);
79 | if (proot)
80 | droot = RootContainer("Root Container",&proot);
81 |
82 | // Some containers with docks attached
83 | static bool pcont = true;
84 | ImGui::SetNextWindowPos(ImVec2(270,20),ImGuiSetCond_FirstUseEver);
85 | ImGui::SetNextWindowSize(ImVec2(300,300),ImGuiSetCond_FirstUseEver);
86 | Dock *dcont1 = nullptr;
87 | if (pcont)
88 | dcont1 = ImGui::Container("One Container",&pcont);
89 | if (first)
90 | dcont1->setDetachedDockSize(200.f, 200.f);
91 |
92 | ImGui::SetNextWindowPos(ImVec2(270,370),ImGuiSetCond_FirstUseEver);
93 | ImGui::SetNextWindowSize(ImVec2(300,300),ImGuiSetCond_FirstUseEver);
94 | Dock *dcont2 = ImGui::Container("Two Container",nullptr,ImGuiWindowFlags_NoResize|
95 | ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoBringToFrontOnFocus);
96 | if (first)
97 | dcont2->setDetachedDockSize(200.f, 200.f);
98 |
99 | // Some containers unattached on the side
100 | static bool popen3[5] = {true,true,true,true,true};
101 | for (int i=0;i<5;i++){
102 | if (popen3[i]){
103 | SetNextWindowPos(ImVec2(20.f,290.f),ImGuiSetCond_FirstUseEver);
104 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
105 | char tmp[16];
106 | sprintf(tmp,"Container #%d",i);
107 | ImGui::Container(tmp,&(popen3[i]));
108 | }
109 | }
110 |
111 | // Some docks unattached on the side
112 | static bool popen[10] = {true,true,true,true,true,true,true,true,true,true};
113 | for (int i=0;i<10;i++){
114 | if (popen[i]){
115 | SetNextWindowPos(ImVec2(20.f,40.f),ImGuiSetCond_FirstUseEver);
116 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
117 | char tmp[16];
118 | sprintf(tmp,"Dock #%d",i);
119 | if (BeginDock(tmp,&(popen[i]))){
120 | Text("Hello, world!");
121 | if (Button("Click me!")){
122 | printf("Clicked in dock %d\n",i);
123 | }
124 | }
125 | EndDock();
126 | }
127 | }
128 |
129 | // Some docks attached to a container
130 | static Dock *pwhich[5] = {dcont1,dcont2,dcont1,dcont2,dcont1};
131 | static bool popen2[3] = {true,true,true};
132 | for (int i=0;i<3;i++){
133 | if (popen2[i]){
134 | char tmp[16];
135 | sprintf(tmp,"Dck #%d",i);
136 | if (BeginDock(tmp,&(popen2[i]),0,0,pwhich[i])){
137 | Text("Hello, world!");
138 | if (Button("Click me!")){
139 | printf("Clicked in dock %d\n",i);
140 | }
141 | }
142 | Dock *dtmp = GetCurrentDock();
143 | EndDock();
144 | if (first)
145 | dtmp->setDetachedDockSize(100.f, 100.f);
146 | }
147 | }
148 | for (int i=3;i<5;i++){
149 | char tmp[16];
150 | sprintf(tmp,"Dck #%d",i);
151 | if (BeginDock(tmp,nullptr,0,0,pwhich[i])){
152 | Text("You can not close me.");
153 | if (Button("Click me!")){
154 | printf("Clicked in dock %d\n",i);
155 | }
156 | }
157 | Dock *dtmp = GetCurrentDock();
158 | EndDock();
159 | if (first)
160 | dtmp->setDetachedDockSize(100.f, 100.f);
161 | }
162 |
163 | // Some more docks attached to the root container
164 | if (BeginDock("Bleh1",nullptr)){
165 | Text("Bleh1.");
166 | if (Button("Click me!")){
167 | printf("Clicked in dock Bleh1\n");
168 | }
169 | }
170 | Dock *dbleh1 = GetCurrentDock();
171 | EndDock();
172 | if (first)
173 | dbleh1->setDetachedDockSize(100.f, 100.f);
174 | if (BeginDock("Bleh2",nullptr,ImGuiWindowFlags_NoResize)){
175 | Text("Bleh2.");
176 | if (Button("Click me!")){
177 | printf("Clicked in dock Bleh2\n");
178 | }
179 | }
180 | Dock *dbleh2 = GetCurrentDock();
181 | EndDock();
182 | if (first)
183 | dbleh2->setDetachedDockSize(100.f, 100.f);
184 |
185 | // // Dock some containers and docks in the root container
186 | // if (first){
187 | // // 1:top, 2:right, 3:bottom, 4:left, 5:replace
188 | // droot->newDockRoot(dcont1,5); // replace the automatic container
189 |
190 | // dcont1->newDockRoot(dcont2,4); // dcont2 on the left of dcont1
191 | // dcont1->setSlidingBarPosition(4,0.3f); // set the bar on the left of dcont1
192 |
193 | // // dock bleh1 below dcont1; save the created automatic container in dtmp
194 | // Dock *dtmp = dcont1->newDockRoot(dbleh1,3);
195 | // dcont1->setSlidingBarPosition(3,0.4f);
196 |
197 | // // dock bleh2 on the right of bleh1
198 | // dtmp->newDockRoot(dbleh2,2);
199 | // dcont1->setSlidingBarPosition(2,0.3f);
200 | // }
201 |
202 | // Draw the current scene
203 | int w, h;
204 | glfwGetFramebufferSize(rootwin,&w,&h);
205 | glViewport(0,0,w,h);
206 | glClearColor(1.0f,0.8f,0.5f,0.0f);
207 | glClear(GL_COLOR_BUFFER_BIT);
208 |
209 | // Render and swap
210 | Render();
211 | glfwSwapBuffers(rootwin);
212 | first = false;
213 | }
214 |
215 | // Cleanup
216 | ShutdownDock();
217 | ImGui_ImplGlfwGL2_Shutdown();
218 | glfwTerminate();
219 |
220 | return 0;
221 | }
222 |
223 |
--------------------------------------------------------------------------------
/examples/widgets.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017 Alberto Otero de la Roza
3 | .
4 |
5 | imgui-goodies is free software: you can redistribute it and/or
6 | modify it under the terms of the GNU General Public License as
7 | published by the Free Software Foundation, either version 3 of the
8 | License, or (at your option) any later version.
9 |
10 | imgui-goodies is distributed in the hope that it will be useful, but
11 | WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | using namespace std;
31 | using namespace ImGui;
32 |
33 | static void error_callback(int error, const char* description){
34 | fprintf(stderr, "Error %d: %s\n", error, description);
35 | }
36 |
37 | int main(int argc, char *argv[]){
38 | // Initialize
39 | glfwSetErrorCallback(error_callback);
40 | if (!glfwInit()) exit(EXIT_FAILURE);
41 |
42 | // Set up window
43 | GLFWwindow* rootwin = glfwCreateWindow(1280, 720, "gcritic2", nullptr, nullptr);
44 | assert(rootwin!=nullptr);
45 | glfwMakeContextCurrent(rootwin);
46 |
47 | // Setup ImGui binding
48 | ImGui_ImplGlfwGL2_Init(rootwin, true);
49 |
50 | // GUI settings
51 | ImGuiIO& io = GetIO();
52 | io.IniFilename = nullptr;
53 |
54 | // Main loop
55 | while (!glfwWindowShouldClose(rootwin)){
56 | // New frame
57 | glfwPollEvents();
58 | ImGui_ImplGlfwGL2_NewFrame();
59 | ImGuiContext *g = GetCurrentContext();
60 |
61 | // Main menu bar
62 | if (BeginMainMenuBar()){
63 | if (BeginMenu("File")){
64 | if (MenuItem("Quit","Ctrl+Q"))
65 | glfwSetWindowShouldClose(rootwin, GLFW_TRUE);
66 | EndMenu();
67 | }
68 | SameLine(0, GetWindowSize().x-250.);
69 | Text("%.3f ms/frame (%.1f FPS)", 1000.0f / GetIO().Framerate, GetIO().Framerate);
70 | }
71 | EndMainMenuBar();
72 |
73 | // Sliding bar example
74 | SetNextWindowPos(ImVec2(20.f,40.f),ImGuiSetCond_FirstUseEver);
75 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
76 | if (Begin("Sliding bar example")){
77 | ImGuiWindow* win = GetCurrentWindow();
78 | static float xbar = 0.5f;
79 | ImVec2 pos, size;
80 | pos = win->Pos;
81 | size = win->Size;
82 | size.x = 8.f;
83 | pos.y += win->TitleBarHeight();
84 | size.y -= win->TitleBarHeight();
85 |
86 | float x0 = win->Pos.x;
87 | float x1 = win->Pos.x+win->Size.x-size.x;
88 | pos.x = x0 + xbar * (x1-x0);
89 |
90 | SlidingBar("slider", win, &pos, size, x0, x1, 1);
91 | xbar = (pos.x - x0 ) / (x1-x0);
92 | }
93 | End();
94 |
95 | // ButtonWithX example
96 | SetNextWindowPos(ImVec2(270.f,40.f),ImGuiSetCond_FirstUseEver);
97 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
98 | if (Begin("Button with X example")){
99 | bool p_open = true, dragged, dclicked, closeclicked;
100 | bool clicked = ButtonWithX("Click me!", ImVec2(80.f,20.f), false, &p_open, &dragged, &dclicked);
101 | if (clicked)
102 | printf("Clicked!\n");
103 | if (!p_open)
104 | printf(">X< clicked!\n");
105 | if (dragged)
106 | Text("Dragged!\n");
107 | if (dclicked)
108 | printf("Double clicked!\n");
109 | }
110 | End();
111 |
112 | // ButtonWithX example
113 | SetNextWindowPos(ImVec2(520.f,40.f),ImGuiSetCond_FirstUseEver);
114 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
115 | if (Begin("Lift grip example")){
116 | ImGuiWindow* win = GetCurrentWindow();
117 | bool lifted = LiftGrip("Liftgrip", win);
118 | if (lifted)
119 | Text("Lifted!\n");
120 | }
121 | End();
122 |
123 | // ResizeGripOther example.
124 | SetNextWindowPos(ImVec2(20.f,290.f),ImGuiSetCond_FirstUseEver);
125 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
126 | if (Begin("Controlled window",nullptr,ImGuiWindowFlags_NoResize))
127 | Text("Resize me!\n");
128 | TextWrapped("Use this other window's grip ----->\n");
129 | ImGuiWindow* win1 = GetCurrentWindow();
130 | End();
131 |
132 | // ResizeGripOther example.
133 | SetNextWindowPos(ImVec2(270.f,290.f),ImGuiSetCond_FirstUseEver);
134 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
135 | if (Begin("Parent window",nullptr,ImGuiWindowFlags_NoResize)){
136 | ImGuiWindow* win2 = GetCurrentWindow();
137 | TextWrapped("Use this grip to resize the left window.\n");
138 | ResizeGripOther("resizegrip", win2, win1);
139 | }
140 | End();
141 |
142 | // ToolTip example.
143 | SetNextWindowPos(ImVec2(520.f,290.f),ImGuiSetCond_FirstUseEver);
144 | SetNextWindowSize(ImVec2(200.f,200.f),ImGuiSetCond_FirstUseEver);
145 | if (Begin("Delayed tooltips example")){
146 | const float delay = 1.5f;
147 | const float maxwidth = 450.f;
148 |
149 | ImGuiWindow* win2 = GetCurrentWindow();
150 | PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f,0.f));
151 | PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 0.5f, 0.f, 1.f));
152 | PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.f, 1.f, 1.f));
153 | Button("A",ImVec2(20.f,20.f)); SameLine();
154 | AttachTooltip("A is for Apple",delay,maxwidth,io.FontDefault);
155 | Button("B",ImVec2(20.f,20.f)); SameLine();
156 | AttachTooltip("B is for Ball",delay,maxwidth,io.FontDefault);
157 | Button("C",ImVec2(20.f,20.f));
158 | AttachTooltip("C is for Cat",delay,maxwidth,io.FontDefault);
159 | Button("D",ImVec2(20.f,20.f)); SameLine();
160 | AttachTooltip("D is for Dog",delay,maxwidth,io.FontDefault);
161 | Button("E",ImVec2(20.f,20.f)); SameLine();
162 | AttachTooltip("E is for Elephant",delay,maxwidth,io.FontDefault);
163 | Button("F",ImVec2(20.f,20.f));
164 | AttachTooltip("F is for Fish",delay,maxwidth,io.FontDefault);
165 | PopStyleColor(2);
166 | PopStyleVar();
167 | }
168 | End();
169 |
170 | // Draw the current scene
171 | int w, h;
172 | glfwGetFramebufferSize(rootwin,&w,&h);
173 | glViewport(0,0,w,h);
174 | glClearColor(1.0f,1.0f,1.0f,0.0f);
175 | glClear(GL_COLOR_BUFFER_BIT);
176 |
177 | // Render and swap
178 | Render();
179 | glfwSwapBuffers(rootwin);
180 | }
181 |
182 | // Cleanup
183 | ShutdownDock();
184 | ImGui_ImplGlfwGL2_Shutdown();
185 | glfwTerminate();
186 |
187 | return 0;
188 | }
189 |
190 |
--------------------------------------------------------------------------------
/images/dock_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aoterodelaroza/imgui-goodies/5d998850931a4bd2b312445e5eb4173de6d0b651/images/dock_example.gif
--------------------------------------------------------------------------------
/images/ogv2gif.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | # Dawid Drozd
3 | # https://unix.stackexchange.com/questions/35282/convert-ogv-video-to-gif-animation
4 |
5 | inputFile=$1
6 |
7 | FPS=15
8 | WIDTH=320
9 |
10 | #Generate palette for better quality
11 | ffmpeg -i $inputFile -vf fps=$FPS,scale=$WIDTH:-1:flags=lanczos,palettegen tmp_palette.png
12 |
13 | #Generate gif using palette
14 | ffmpeg -i $inputFile -i tmp_palette.png -loop 0 -filter_complex "fps=$FPS,scale=$WIDTH:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
15 |
16 | rm tmp_palette.png
17 |
--------------------------------------------------------------------------------
/images/tooltip_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aoterodelaroza/imgui-goodies/5d998850931a4bd2b312445e5eb4173de6d0b651/images/tooltip_example.gif
--------------------------------------------------------------------------------
/imgui/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | RM=rm -f
3 | CPPFLAGS=-I./ $(shell pkg-config --cflags glfw3 glu gl) -Wall -Wformat -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++11 -w -g
4 | LDFLAGS=-g $(shell pkg-config --libs glfw3 glu gl)
5 |
6 | SRCS=imgui.cpp imgui_demo.cpp imgui_draw.cpp imgui_impl_glfw.cpp
7 | OBJS=$(subst .cpp,.o,$(SRCS))
8 |
9 | all: .depend $(OBJS)
10 | @true
11 |
12 | .depend: $(SRCS)
13 | $(RM) ./.depend
14 | $(CXX) $(CPPFLAGS) -MM $^>>./.depend;
15 |
16 | clean:
17 | $(RM) $(OBJS)
18 |
19 | distclean: clean
20 | $(RM) *~ .depend
21 |
22 | include .depend
23 |
--------------------------------------------------------------------------------
/imgui/imconfig.h:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | // USER IMPLEMENTATION
3 | // This file contains compile-time options for ImGui.
4 | // Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO().
5 | //-----------------------------------------------------------------------------
6 |
7 | #pragma once
8 |
9 | //---- Define assertion handler. Defaults to calling assert().
10 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
11 |
12 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
13 | //#define IMGUI_API __declspec( dllexport )
14 | //#define IMGUI_API __declspec( dllimport )
15 |
16 | //---- Include imgui_user.h at the end of imgui.h
17 | //#define IMGUI_INCLUDE_IMGUI_USER_H
18 |
19 | //---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions)
20 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
21 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS
22 |
23 | //---- Don't implement test window functionality (ShowTestWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty)
24 | //---- It is very strongly recommended to NOT disable the test windows. Please read the comment at the top of imgui_demo.cpp to learn why.
25 | //#define IMGUI_DISABLE_TEST_WINDOWS
26 |
27 | //---- Don't define obsolete functions names
28 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
29 |
30 | //---- Pack colors to BGRA instead of RGBA (remove need to post process vertex buffer in back ends)
31 | //#define IMGUI_USE_BGRA_PACKED_COLOR
32 |
33 | //---- Implement STB libraries in a namespace to avoid conflicts
34 | //#define IMGUI_STB_NAMESPACE ImGuiStb
35 |
36 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
37 | /*
38 | #define IM_VEC2_CLASS_EXTRA \
39 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
40 | operator MyVec2() const { return MyVec2(x,y); }
41 |
42 | #define IM_VEC4_CLASS_EXTRA \
43 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
44 | operator MyVec4() const { return MyVec4(x,y,z,w); }
45 | */
46 |
47 | //---- Use 32-bit vertex indices (instead of default: 16-bit) to allow meshes with more than 64K vertices
48 | //#define ImDrawIdx unsigned int
49 |
50 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
51 | //---- e.g. create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers.
52 | /*
53 | namespace ImGui
54 | {
55 | void Value(const char* prefix, const MyMatrix44& v, const char* float_format = NULL);
56 | }
57 | */
58 |
59 |
--------------------------------------------------------------------------------
/imgui/imgui_impl_glfw.cpp:
--------------------------------------------------------------------------------
1 | // ImGui GLFW binding with OpenGL (legacy, fixed pipeline)
2 | // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
3 | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 |
5 | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
6 | // **Prefer using the code in the opengl3_example/ folder**
7 | // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
8 | // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
9 | // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
10 | // confuse your GPU driver.
11 | // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
12 |
13 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
14 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
15 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
16 | // https://github.com/ocornut/imgui
17 |
18 | #include
19 | #include "imgui_impl_glfw.h"
20 |
21 | // GLFW
22 | #include
23 | #ifdef _WIN32
24 | #undef APIENTRY
25 | #define GLFW_EXPOSE_NATIVE_WIN32
26 | #define GLFW_EXPOSE_NATIVE_WGL
27 | #include
28 | #endif
29 |
30 | // Data
31 | static GLFWwindow* g_Window = NULL;
32 | static double g_Time = 0.0f;
33 | static bool g_MouseJustPressed[3] = { false, false, false };
34 | static float g_MouseWheel = 0.0f;
35 | static GLuint g_FontTexture = 0;
36 |
37 | // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
38 | void ImGui_ImplGlfwGL2_RenderDrawLists(ImDrawData* draw_data)
39 | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
40 | // If text or lines are blurry when integrating ImGui in your engine: in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
41 | {
42 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
43 | ImGuiIO& io = ImGui::GetIO();
44 | int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
45 | int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
46 | if (fb_width == 0 || fb_height == 0)
47 | return;
48 | draw_data->ScaleClipRects(io.DisplayFramebufferScale);
49 |
50 | // We are using the OpenGL fixed pipeline to make the example code simpler to read!
51 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
52 | GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
53 | GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
54 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
55 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
56 | glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
57 | glEnable(GL_BLEND);
58 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
59 | glDisable(GL_CULL_FACE);
60 | glDisable(GL_DEPTH_TEST);
61 | glEnable(GL_SCISSOR_TEST);
62 | glEnableClientState(GL_VERTEX_ARRAY);
63 | glEnableClientState(GL_TEXTURE_COORD_ARRAY);
64 | glEnableClientState(GL_COLOR_ARRAY);
65 | glEnable(GL_TEXTURE_2D);
66 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
67 | //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
68 |
69 | // Setup viewport, orthographic projection matrix
70 | glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
71 | glMatrixMode(GL_PROJECTION);
72 | glPushMatrix();
73 | glLoadIdentity();
74 | glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
75 | glMatrixMode(GL_MODELVIEW);
76 | glPushMatrix();
77 | glLoadIdentity();
78 |
79 | // Render command lists
80 | #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
81 | for (int n = 0; n < draw_data->CmdListsCount; n++)
82 | {
83 | const ImDrawList* cmd_list = draw_data->CmdLists[n];
84 | const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
85 | const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
86 | glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, pos)));
87 | glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, uv)));
88 | glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, col)));
89 |
90 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
91 | {
92 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
93 | if (pcmd->UserCallback)
94 | {
95 | pcmd->UserCallback(cmd_list, pcmd);
96 | }
97 | else
98 | {
99 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
100 | glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
101 | glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
102 | }
103 | idx_buffer += pcmd->ElemCount;
104 | }
105 | }
106 | #undef OFFSETOF
107 |
108 | // Restore modified state
109 | glDisableClientState(GL_COLOR_ARRAY);
110 | glDisableClientState(GL_TEXTURE_COORD_ARRAY);
111 | glDisableClientState(GL_VERTEX_ARRAY);
112 | glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
113 | glMatrixMode(GL_MODELVIEW);
114 | glPopMatrix();
115 | glMatrixMode(GL_PROJECTION);
116 | glPopMatrix();
117 | glPopAttrib();
118 | glPolygonMode(GL_FRONT, last_polygon_mode[0]); glPolygonMode(GL_BACK, last_polygon_mode[1]);
119 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
120 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
121 | }
122 |
123 | static const char* ImGui_ImplGlfwGL2_GetClipboardText(void* user_data)
124 | {
125 | return glfwGetClipboardString((GLFWwindow*)user_data);
126 | }
127 |
128 | static void ImGui_ImplGlfwGL2_SetClipboardText(void* user_data, const char* text)
129 | {
130 | glfwSetClipboardString((GLFWwindow*)user_data, text);
131 | }
132 |
133 | void ImGui_ImplGlfwGL2_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/)
134 | {
135 | if (action == GLFW_PRESS && button >= 0 && button < 3)
136 | g_MouseJustPressed[button] = true;
137 | }
138 |
139 | void ImGui_ImplGlfwGL2_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset)
140 | {
141 | g_MouseWheel += (float)yoffset; // Use fractional mouse wheel.
142 | }
143 |
144 | void ImGui_ImplGlfwGL2_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
145 | {
146 | ImGuiIO& io = ImGui::GetIO();
147 | if (action == GLFW_PRESS)
148 | io.KeysDown[key] = true;
149 | if (action == GLFW_RELEASE)
150 | io.KeysDown[key] = false;
151 |
152 | (void)mods; // Modifiers are not reliable across systems
153 | io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
154 | io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
155 | io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
156 | io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
157 | }
158 |
159 | void ImGui_ImplGlfwGL2_CharCallback(GLFWwindow*, unsigned int c)
160 | {
161 | ImGuiIO& io = ImGui::GetIO();
162 | if (c > 0 && c < 0x10000)
163 | io.AddInputCharacter((unsigned short)c);
164 | }
165 |
166 | bool ImGui_ImplGlfwGL2_CreateDeviceObjects()
167 | {
168 | // Build texture atlas
169 | ImGuiIO& io = ImGui::GetIO();
170 | unsigned char* pixels;
171 | int width, height;
172 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
173 |
174 | // Upload texture to graphics system
175 | GLint last_texture;
176 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
177 | glGenTextures(1, &g_FontTexture);
178 | glBindTexture(GL_TEXTURE_2D, g_FontTexture);
179 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
180 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
181 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
182 |
183 | // Store our identifier
184 | io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
185 |
186 | // Restore state
187 | glBindTexture(GL_TEXTURE_2D, last_texture);
188 |
189 | return true;
190 | }
191 |
192 | void ImGui_ImplGlfwGL2_InvalidateDeviceObjects()
193 | {
194 | if (g_FontTexture)
195 | {
196 | glDeleteTextures(1, &g_FontTexture);
197 | ImGui::GetIO().Fonts->TexID = 0;
198 | g_FontTexture = 0;
199 | }
200 | }
201 |
202 | bool ImGui_ImplGlfwGL2_Init(GLFWwindow* window, bool install_callbacks)
203 | {
204 | g_Window = window;
205 |
206 | ImGuiIO& io = ImGui::GetIO();
207 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
208 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
209 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
210 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
211 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
212 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
213 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
214 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
215 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
216 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
217 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
218 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
219 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
220 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
221 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
222 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
223 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
224 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
225 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
226 |
227 | io.RenderDrawListsFn = ImGui_ImplGlfwGL2_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
228 | io.SetClipboardTextFn = ImGui_ImplGlfwGL2_SetClipboardText;
229 | io.GetClipboardTextFn = ImGui_ImplGlfwGL2_GetClipboardText;
230 | io.ClipboardUserData = g_Window;
231 | #ifdef _WIN32
232 | io.ImeWindowHandle = glfwGetWin32Window(g_Window);
233 | #endif
234 |
235 | if (install_callbacks)
236 | {
237 | glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL2_MouseButtonCallback);
238 | glfwSetScrollCallback(window, ImGui_ImplGlfwGL2_ScrollCallback);
239 | glfwSetKeyCallback(window, ImGui_ImplGlfwGL2_KeyCallback);
240 | glfwSetCharCallback(window, ImGui_ImplGlfwGL2_CharCallback);
241 | }
242 |
243 | return true;
244 | }
245 |
246 | void ImGui_ImplGlfwGL2_Shutdown()
247 | {
248 | ImGui_ImplGlfwGL2_InvalidateDeviceObjects();
249 | ImGui::Shutdown();
250 | }
251 |
252 | void ImGui_ImplGlfwGL2_NewFrame()
253 | {
254 | if (!g_FontTexture)
255 | ImGui_ImplGlfwGL2_CreateDeviceObjects();
256 |
257 | ImGuiIO& io = ImGui::GetIO();
258 |
259 | // Setup display size (every frame to accommodate for window resizing)
260 | int w, h;
261 | int display_w, display_h;
262 | glfwGetWindowSize(g_Window, &w, &h);
263 | glfwGetFramebufferSize(g_Window, &display_w, &display_h);
264 | io.DisplaySize = ImVec2((float)w, (float)h);
265 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
266 |
267 | // Setup time step
268 | double current_time = glfwGetTime();
269 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
270 | g_Time = current_time;
271 |
272 | // Setup inputs
273 | // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
274 | if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
275 | {
276 | if (io.WantMoveMouse)
277 | {
278 | glfwSetCursorPos(g_Window, (double)io.MousePos.x, (double)io.MousePos.y); // Set mouse position if requested by io.WantMoveMouse flag (used when io.NavMovesTrue is enabled by user and using directional navigation)
279 | }
280 | else
281 | {
282 | double mouse_x, mouse_y;
283 | glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
284 | io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Get mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.)
285 | }
286 | }
287 | else
288 | {
289 | io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX);
290 | }
291 |
292 | for (int i = 0; i < 3; i++)
293 | {
294 | // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
295 | io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
296 | g_MouseJustPressed[i] = false;
297 | }
298 |
299 | io.MouseWheel = g_MouseWheel;
300 | g_MouseWheel = 0.0f;
301 |
302 | // Hide OS mouse cursor if ImGui is drawing it
303 | glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
304 |
305 | // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application.
306 | ImGui::NewFrame();
307 | }
308 |
--------------------------------------------------------------------------------
/imgui/imgui_impl_glfw.h:
--------------------------------------------------------------------------------
1 | // ImGui GLFW binding with OpenGL (legacy, fixed pipeline)
2 | // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
3 | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 |
5 | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
6 | // **Prefer using the code in the opengl3_example/ folder**
7 | // See imgui_impl_glfw.cpp for details.
8 |
9 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
10 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
11 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
12 | // https://github.com/ocornut/imgui
13 |
14 | struct GLFWwindow;
15 |
16 | IMGUI_API bool ImGui_ImplGlfwGL2_Init(GLFWwindow* window, bool install_callbacks);
17 | IMGUI_API void ImGui_ImplGlfwGL2_Shutdown();
18 | IMGUI_API void ImGui_ImplGlfwGL2_NewFrame();
19 |
20 | // Use if you want to reset your rendering device without losing ImGui state.
21 | IMGUI_API void ImGui_ImplGlfwGL2_InvalidateDeviceObjects();
22 | IMGUI_API bool ImGui_ImplGlfwGL2_CreateDeviceObjects();
23 |
24 | // GLFW callbacks (registered by default to GLFW if you enable 'install_callbacks' during initialization)
25 | // Provided here if you want to chain callbacks yourself. You may also handle inputs yourself and use those as a reference.
26 | IMGUI_API void ImGui_ImplGlfwGL2_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
27 | IMGUI_API void ImGui_ImplGlfwGL2_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
28 | IMGUI_API void ImGui_ImplGlfwGL2_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
29 | IMGUI_API void ImGui_ImplGlfwGL2_CharCallback(GLFWwindow* window, unsigned int c);
30 |
--------------------------------------------------------------------------------
/imgui/stb_rect_pack.h:
--------------------------------------------------------------------------------
1 | // stb_rect_pack.h - v0.10 - public domain - rectangle packing
2 | // Sean Barrett 2014
3 | //
4 | // Useful for e.g. packing rectangular textures into an atlas.
5 | // Does not do rotation.
6 | //
7 | // Not necessarily the awesomest packing method, but better than
8 | // the totally naive one in stb_truetype (which is primarily what
9 | // this is meant to replace).
10 | //
11 | // Has only had a few tests run, may have issues.
12 | //
13 | // More docs to come.
14 | //
15 | // No memory allocations; uses qsort() and assert() from stdlib.
16 | // Can override those by defining STBRP_SORT and STBRP_ASSERT.
17 | //
18 | // This library currently uses the Skyline Bottom-Left algorithm.
19 | //
20 | // Please note: better rectangle packers are welcome! Please
21 | // implement them to the same API, but with a different init
22 | // function.
23 | //
24 | // Credits
25 | //
26 | // Library
27 | // Sean Barrett
28 | // Minor features
29 | // Martins Mozeiko
30 | // Bugfixes / warning fixes
31 | // Jeremy Jaussaud
32 | //
33 | // Version history:
34 | //
35 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
36 | // 0.09 (2016-08-27) fix compiler warnings
37 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
38 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
39 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
40 | // 0.05: added STBRP_ASSERT to allow replacing assert
41 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support
42 | // 0.01: initial release
43 | //
44 | // LICENSE
45 | //
46 | // This software is dual-licensed to the public domain and under the following
47 | // license: you are granted a perpetual, irrevocable license to copy, modify,
48 | // publish, and distribute this file as you see fit.
49 |
50 | //////////////////////////////////////////////////////////////////////////////
51 | //
52 | // INCLUDE SECTION
53 | //
54 |
55 | #ifndef STB_INCLUDE_STB_RECT_PACK_H
56 | #define STB_INCLUDE_STB_RECT_PACK_H
57 |
58 | #define STB_RECT_PACK_VERSION 1
59 |
60 | #ifdef STBRP_STATIC
61 | #define STBRP_DEF static
62 | #else
63 | #define STBRP_DEF extern
64 | #endif
65 |
66 | #ifdef __cplusplus
67 | extern "C" {
68 | #endif
69 |
70 | typedef struct stbrp_context stbrp_context;
71 | typedef struct stbrp_node stbrp_node;
72 | typedef struct stbrp_rect stbrp_rect;
73 |
74 | #ifdef STBRP_LARGE_RECTS
75 | typedef int stbrp_coord;
76 | #else
77 | typedef unsigned short stbrp_coord;
78 | #endif
79 |
80 | STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
81 | // Assign packed locations to rectangles. The rectangles are of type
82 | // 'stbrp_rect' defined below, stored in the array 'rects', and there
83 | // are 'num_rects' many of them.
84 | //
85 | // Rectangles which are successfully packed have the 'was_packed' flag
86 | // set to a non-zero value and 'x' and 'y' store the minimum location
87 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left
88 | // if you imagine y increasing downwards). Rectangles which do not fit
89 | // have the 'was_packed' flag set to 0.
90 | //
91 | // You should not try to access the 'rects' array from another thread
92 | // while this function is running, as the function temporarily reorders
93 | // the array while it executes.
94 | //
95 | // To pack into another rectangle, you need to call stbrp_init_target
96 | // again. To continue packing into the same rectangle, you can call
97 | // this function again. Calling this multiple times with multiple rect
98 | // arrays will probably produce worse packing results than calling it
99 | // a single time with the full rectangle array, but the option is
100 | // available.
101 |
102 | struct stbrp_rect
103 | {
104 | // reserved for your use:
105 | int id;
106 |
107 | // input:
108 | stbrp_coord w, h;
109 |
110 | // output:
111 | stbrp_coord x, y;
112 | int was_packed; // non-zero if valid packing
113 |
114 | }; // 16 bytes, nominally
115 |
116 |
117 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
118 | // Initialize a rectangle packer to:
119 | // pack a rectangle that is 'width' by 'height' in dimensions
120 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long
121 | //
122 | // You must call this function every time you start packing into a new target.
123 | //
124 | // There is no "shutdown" function. The 'nodes' memory must stay valid for
125 | // the following stbrp_pack_rects() call (or calls), but can be freed after
126 | // the call (or calls) finish.
127 | //
128 | // Note: to guarantee best results, either:
129 | // 1. make sure 'num_nodes' >= 'width'
130 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
131 | //
132 | // If you don't do either of the above things, widths will be quantized to multiples
133 | // of small integers to guarantee the algorithm doesn't run out of temporary storage.
134 | //
135 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm
136 | // may run out of temporary storage and be unable to pack some rectangles.
137 |
138 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
139 | // Optionally call this function after init but before doing any packing to
140 | // change the handling of the out-of-temp-memory scenario, described above.
141 | // If you call init again, this will be reset to the default (false).
142 |
143 |
144 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
145 | // Optionally select which packing heuristic the library should use. Different
146 | // heuristics will produce better/worse results for different data sets.
147 | // If you call init again, this will be reset to the default.
148 |
149 | enum
150 | {
151 | STBRP_HEURISTIC_Skyline_default=0,
152 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
153 | STBRP_HEURISTIC_Skyline_BF_sortHeight
154 | };
155 |
156 |
157 | //////////////////////////////////////////////////////////////////////////////
158 | //
159 | // the details of the following structures don't matter to you, but they must
160 | // be visible so you can handle the memory allocations for them
161 |
162 | struct stbrp_node
163 | {
164 | stbrp_coord x,y;
165 | stbrp_node *next;
166 | };
167 |
168 | struct stbrp_context
169 | {
170 | int width;
171 | int height;
172 | int align;
173 | int init_mode;
174 | int heuristic;
175 | int num_nodes;
176 | stbrp_node *active_head;
177 | stbrp_node *free_head;
178 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
179 | };
180 |
181 | #ifdef __cplusplus
182 | }
183 | #endif
184 |
185 | #endif
186 |
187 | //////////////////////////////////////////////////////////////////////////////
188 | //
189 | // IMPLEMENTATION SECTION
190 | //
191 |
192 | #ifdef STB_RECT_PACK_IMPLEMENTATION
193 | #ifndef STBRP_SORT
194 | #include
195 | #define STBRP_SORT qsort
196 | #endif
197 |
198 | #ifndef STBRP_ASSERT
199 | #include
200 | #define STBRP_ASSERT assert
201 | #endif
202 |
203 | #ifdef _MSC_VER
204 | #define STBRP__NOTUSED(v) (void)(v)
205 | #else
206 | #define STBRP__NOTUSED(v) (void)sizeof(v)
207 | #endif
208 |
209 | enum
210 | {
211 | STBRP__INIT_skyline = 1
212 | };
213 |
214 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
215 | {
216 | switch (context->init_mode) {
217 | case STBRP__INIT_skyline:
218 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
219 | context->heuristic = heuristic;
220 | break;
221 | default:
222 | STBRP_ASSERT(0);
223 | }
224 | }
225 |
226 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
227 | {
228 | if (allow_out_of_mem)
229 | // if it's ok to run out of memory, then don't bother aligning them;
230 | // this gives better packing, but may fail due to OOM (even though
231 | // the rectangles easily fit). @TODO a smarter approach would be to only
232 | // quantize once we've hit OOM, then we could get rid of this parameter.
233 | context->align = 1;
234 | else {
235 | // if it's not ok to run out of memory, then quantize the widths
236 | // so that num_nodes is always enough nodes.
237 | //
238 | // I.e. num_nodes * align >= width
239 | // align >= width / num_nodes
240 | // align = ceil(width/num_nodes)
241 |
242 | context->align = (context->width + context->num_nodes-1) / context->num_nodes;
243 | }
244 | }
245 |
246 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
247 | {
248 | int i;
249 | #ifndef STBRP_LARGE_RECTS
250 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
251 | #endif
252 |
253 | for (i=0; i < num_nodes-1; ++i)
254 | nodes[i].next = &nodes[i+1];
255 | nodes[i].next = NULL;
256 | context->init_mode = STBRP__INIT_skyline;
257 | context->heuristic = STBRP_HEURISTIC_Skyline_default;
258 | context->free_head = &nodes[0];
259 | context->active_head = &context->extra[0];
260 | context->width = width;
261 | context->height = height;
262 | context->num_nodes = num_nodes;
263 | stbrp_setup_allow_out_of_mem(context, 0);
264 |
265 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
266 | context->extra[0].x = 0;
267 | context->extra[0].y = 0;
268 | context->extra[0].next = &context->extra[1];
269 | context->extra[1].x = (stbrp_coord) width;
270 | #ifdef STBRP_LARGE_RECTS
271 | context->extra[1].y = (1<<30);
272 | #else
273 | context->extra[1].y = 65535;
274 | #endif
275 | context->extra[1].next = NULL;
276 | }
277 |
278 | // find minimum y position if it starts at x1
279 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
280 | {
281 | stbrp_node *node = first;
282 | int x1 = x0 + width;
283 | int min_y, visited_width, waste_area;
284 |
285 | STBRP__NOTUSED(c);
286 |
287 | STBRP_ASSERT(first->x <= x0);
288 |
289 | #if 0
290 | // skip in case we're past the node
291 | while (node->next->x <= x0)
292 | ++node;
293 | #else
294 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
295 | #endif
296 |
297 | STBRP_ASSERT(node->x <= x0);
298 |
299 | min_y = 0;
300 | waste_area = 0;
301 | visited_width = 0;
302 | while (node->x < x1) {
303 | if (node->y > min_y) {
304 | // raise min_y higher.
305 | // we've accounted for all waste up to min_y,
306 | // but we'll now add more waste for everything we've visted
307 | waste_area += visited_width * (node->y - min_y);
308 | min_y = node->y;
309 | // the first time through, visited_width might be reduced
310 | if (node->x < x0)
311 | visited_width += node->next->x - x0;
312 | else
313 | visited_width += node->next->x - node->x;
314 | } else {
315 | // add waste area
316 | int under_width = node->next->x - node->x;
317 | if (under_width + visited_width > width)
318 | under_width = width - visited_width;
319 | waste_area += under_width * (min_y - node->y);
320 | visited_width += under_width;
321 | }
322 | node = node->next;
323 | }
324 |
325 | *pwaste = waste_area;
326 | return min_y;
327 | }
328 |
329 | typedef struct
330 | {
331 | int x,y;
332 | stbrp_node **prev_link;
333 | } stbrp__findresult;
334 |
335 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
336 | {
337 | int best_waste = (1<<30), best_x, best_y = (1 << 30);
338 | stbrp__findresult fr;
339 | stbrp_node **prev, *node, *tail, **best = NULL;
340 |
341 | // align to multiple of c->align
342 | width = (width + c->align - 1);
343 | width -= width % c->align;
344 | STBRP_ASSERT(width % c->align == 0);
345 |
346 | node = c->active_head;
347 | prev = &c->active_head;
348 | while (node->x + width <= c->width) {
349 | int y,waste;
350 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
351 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
352 | // bottom left
353 | if (y < best_y) {
354 | best_y = y;
355 | best = prev;
356 | }
357 | } else {
358 | // best-fit
359 | if (y + height <= c->height) {
360 | // can only use it if it first vertically
361 | if (y < best_y || (y == best_y && waste < best_waste)) {
362 | best_y = y;
363 | best_waste = waste;
364 | best = prev;
365 | }
366 | }
367 | }
368 | prev = &node->next;
369 | node = node->next;
370 | }
371 |
372 | best_x = (best == NULL) ? 0 : (*best)->x;
373 |
374 | // if doing best-fit (BF), we also have to try aligning right edge to each node position
375 | //
376 | // e.g, if fitting
377 | //
378 | // ____________________
379 | // |____________________|
380 | //
381 | // into
382 | //
383 | // | |
384 | // | ____________|
385 | // |____________|
386 | //
387 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
388 | //
389 | // This makes BF take about 2x the time
390 |
391 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
392 | tail = c->active_head;
393 | node = c->active_head;
394 | prev = &c->active_head;
395 | // find first node that's admissible
396 | while (tail->x < width)
397 | tail = tail->next;
398 | while (tail) {
399 | int xpos = tail->x - width;
400 | int y,waste;
401 | STBRP_ASSERT(xpos >= 0);
402 | // find the left position that matches this
403 | while (node->next->x <= xpos) {
404 | prev = &node->next;
405 | node = node->next;
406 | }
407 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
408 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
409 | if (y + height < c->height) {
410 | if (y <= best_y) {
411 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
412 | best_x = xpos;
413 | STBRP_ASSERT(y <= best_y);
414 | best_y = y;
415 | best_waste = waste;
416 | best = prev;
417 | }
418 | }
419 | }
420 | tail = tail->next;
421 | }
422 | }
423 |
424 | fr.prev_link = best;
425 | fr.x = best_x;
426 | fr.y = best_y;
427 | return fr;
428 | }
429 |
430 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
431 | {
432 | // find best position according to heuristic
433 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
434 | stbrp_node *node, *cur;
435 |
436 | // bail if:
437 | // 1. it failed
438 | // 2. the best node doesn't fit (we don't always check this)
439 | // 3. we're out of memory
440 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
441 | res.prev_link = NULL;
442 | return res;
443 | }
444 |
445 | // on success, create new node
446 | node = context->free_head;
447 | node->x = (stbrp_coord) res.x;
448 | node->y = (stbrp_coord) (res.y + height);
449 |
450 | context->free_head = node->next;
451 |
452 | // insert the new node into the right starting point, and
453 | // let 'cur' point to the remaining nodes needing to be
454 | // stiched back in
455 |
456 | cur = *res.prev_link;
457 | if (cur->x < res.x) {
458 | // preserve the existing one, so start testing with the next one
459 | stbrp_node *next = cur->next;
460 | cur->next = node;
461 | cur = next;
462 | } else {
463 | *res.prev_link = node;
464 | }
465 |
466 | // from here, traverse cur and free the nodes, until we get to one
467 | // that shouldn't be freed
468 | while (cur->next && cur->next->x <= res.x + width) {
469 | stbrp_node *next = cur->next;
470 | // move the current node to the free list
471 | cur->next = context->free_head;
472 | context->free_head = cur;
473 | cur = next;
474 | }
475 |
476 | // stitch the list back in
477 | node->next = cur;
478 |
479 | if (cur->x < res.x + width)
480 | cur->x = (stbrp_coord) (res.x + width);
481 |
482 | #ifdef _DEBUG
483 | cur = context->active_head;
484 | while (cur->x < context->width) {
485 | STBRP_ASSERT(cur->x < cur->next->x);
486 | cur = cur->next;
487 | }
488 | STBRP_ASSERT(cur->next == NULL);
489 |
490 | {
491 | stbrp_node *L1 = NULL, *L2 = NULL;
492 | int count=0;
493 | cur = context->active_head;
494 | while (cur) {
495 | L1 = cur;
496 | cur = cur->next;
497 | ++count;
498 | }
499 | cur = context->free_head;
500 | while (cur) {
501 | L2 = cur;
502 | cur = cur->next;
503 | ++count;
504 | }
505 | STBRP_ASSERT(count == context->num_nodes+2);
506 | }
507 | #endif
508 |
509 | return res;
510 | }
511 |
512 | static int rect_height_compare(const void *a, const void *b)
513 | {
514 | const stbrp_rect *p = (const stbrp_rect *) a;
515 | const stbrp_rect *q = (const stbrp_rect *) b;
516 | if (p->h > q->h)
517 | return -1;
518 | if (p->h < q->h)
519 | return 1;
520 | return (p->w > q->w) ? -1 : (p->w < q->w);
521 | }
522 |
523 | static int rect_width_compare(const void *a, const void *b)
524 | {
525 | const stbrp_rect *p = (const stbrp_rect *) a;
526 | const stbrp_rect *q = (const stbrp_rect *) b;
527 | if (p->w > q->w)
528 | return -1;
529 | if (p->w < q->w)
530 | return 1;
531 | return (p->h > q->h) ? -1 : (p->h < q->h);
532 | }
533 |
534 | static int rect_original_order(const void *a, const void *b)
535 | {
536 | const stbrp_rect *p = (const stbrp_rect *) a;
537 | const stbrp_rect *q = (const stbrp_rect *) b;
538 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
539 | }
540 |
541 | #ifdef STBRP_LARGE_RECTS
542 | #define STBRP__MAXVAL 0xffffffff
543 | #else
544 | #define STBRP__MAXVAL 0xffff
545 | #endif
546 |
547 | STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
548 | {
549 | int i;
550 |
551 | // we use the 'was_packed' field internally to allow sorting/unsorting
552 | for (i=0; i < num_rects; ++i) {
553 | rects[i].was_packed = i;
554 | #ifndef STBRP_LARGE_RECTS
555 | STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
556 | #endif
557 | }
558 |
559 | // sort according to heuristic
560 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
561 |
562 | for (i=0; i < num_rects; ++i) {
563 | if (rects[i].w == 0 || rects[i].h == 0) {
564 | rects[i].x = rects[i].y = 0; // empty rect needs no space
565 | } else {
566 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
567 | if (fr.prev_link) {
568 | rects[i].x = (stbrp_coord) fr.x;
569 | rects[i].y = (stbrp_coord) fr.y;
570 | } else {
571 | rects[i].x = rects[i].y = STBRP__MAXVAL;
572 | }
573 | }
574 | }
575 |
576 | // unsort
577 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
578 |
579 | // set was_packed flags
580 | for (i=0; i < num_rects; ++i)
581 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
582 | }
583 | #endif
584 |
--------------------------------------------------------------------------------
/imgui/stb_textedit.h:
--------------------------------------------------------------------------------
1 | // [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb
2 | // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815)
3 | // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715)
4 | // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681)
5 | // [ImGui] - fixed some minor warnings
6 |
7 | // stb_textedit.h - v1.9 - public domain - Sean Barrett
8 | // Development of this library was sponsored by RAD Game Tools
9 | //
10 | // This C header file implements the guts of a multi-line text-editing
11 | // widget; you implement display, word-wrapping, and low-level string
12 | // insertion/deletion, and stb_textedit will map user inputs into
13 | // insertions & deletions, plus updates to the cursor position,
14 | // selection state, and undo state.
15 | //
16 | // It is intended for use in games and other systems that need to build
17 | // their own custom widgets and which do not have heavy text-editing
18 | // requirements (this library is not recommended for use for editing large
19 | // texts, as its performance does not scale and it has limited undo).
20 | //
21 | // Non-trivial behaviors are modelled after Windows text controls.
22 | //
23 | //
24 | // LICENSE
25 | //
26 | // This software is dual-licensed to the public domain and under the following
27 | // license: you are granted a perpetual, irrevocable license to copy, modify,
28 | // publish, and distribute this file as you see fit.
29 | //
30 | //
31 | // DEPENDENCIES
32 | //
33 | // Uses the C runtime function 'memmove', which you can override
34 | // by defining STB_TEXTEDIT_memmove before the implementation.
35 | // Uses no other functions. Performs no runtime allocations.
36 | //
37 | //
38 | // VERSION HISTORY
39 | //
40 | // 1.9 (2016-08-27) customizable move-by-word
41 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down
42 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0
43 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove
44 | // 1.5 (2014-09-10) add support for secondary keys for OS X
45 | // 1.4 (2014-08-17) fix signed/unsigned warnings
46 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary
47 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code
48 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE )
49 | // 1.0 (2012-07-26) improve documentation, initial public release
50 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode
51 | // 0.2 (2011-11-28) fixes to undo/redo
52 | // 0.1 (2010-07-08) initial version
53 | //
54 | // ADDITIONAL CONTRIBUTORS
55 | //
56 | // Ulf Winklemann: move-by-word in 1.1
57 | // Fabian Giesen: secondary key inputs in 1.5
58 | // Martins Mozeiko: STB_TEXTEDIT_memmove
59 | //
60 | // Bugfixes:
61 | // Scott Graham
62 | // Daniel Keller
63 | // Omar Cornut
64 | //
65 | // USAGE
66 | //
67 | // This file behaves differently depending on what symbols you define
68 | // before including it.
69 | //
70 | //
71 | // Header-file mode:
72 | //
73 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this,
74 | // it will operate in "header file" mode. In this mode, it declares a
75 | // single public symbol, STB_TexteditState, which encapsulates the current
76 | // state of a text widget (except for the string, which you will store
77 | // separately).
78 | //
79 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a
80 | // primitive type that defines a single character (e.g. char, wchar_t, etc).
81 | //
82 | // To save space or increase undo-ability, you can optionally define the
83 | // following things that are used by the undo system:
84 | //
85 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position
86 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow
87 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer
88 | //
89 | // If you don't define these, they are set to permissive types and
90 | // moderate sizes. The undo system does no memory allocations, so
91 | // it grows STB_TexteditState by the worst-case storage which is (in bytes):
92 | //
93 | // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT
94 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT
95 | //
96 | //
97 | // Implementation mode:
98 | //
99 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it
100 | // will compile the implementation of the text edit widget, depending
101 | // on a large number of symbols which must be defined before the include.
102 | //
103 | // The implementation is defined only as static functions. You will then
104 | // need to provide your own APIs in the same file which will access the
105 | // static functions.
106 | //
107 | // The basic concept is that you provide a "string" object which
108 | // behaves like an array of characters. stb_textedit uses indices to
109 | // refer to positions in the string, implicitly representing positions
110 | // in the displayed textedit. This is true for both plain text and
111 | // rich text; even with rich text stb_truetype interacts with your
112 | // code as if there was an array of all the displayed characters.
113 | //
114 | // Symbols that must be the same in header-file and implementation mode:
115 | //
116 | // STB_TEXTEDIT_CHARTYPE the character type
117 | // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position
118 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow
119 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer
120 | //
121 | // Symbols you must define for implementation mode:
122 | //
123 | // STB_TEXTEDIT_STRING the type of object representing a string being edited,
124 | // typically this is a wrapper object with other data you need
125 | //
126 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1))
127 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters
128 | // starting from character #n (see discussion below)
129 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character
130 | // to the xpos of the i+1'th char for a line of characters
131 | // starting at character #n (i.e. accounts for kerning
132 | // with previous char)
133 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
134 | // (return type is int, -1 means not valid to insert)
135 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
136 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
137 | // as manually wordwrapping for end-of-line positioning
138 | //
139 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i
140 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*)
141 | //
142 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key
143 | //
144 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left
145 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right
146 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up
147 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down
148 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME
149 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END
150 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME
151 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END
152 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor
153 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor
154 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo
155 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo
156 | //
157 | // Optional:
158 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
159 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
160 | // required for default WORDLEFT/WORDRIGHT handlers
161 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to
162 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to
163 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
164 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
165 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
166 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line
167 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
168 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
169 | //
170 | // Todo:
171 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
172 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
173 | //
174 | // Keyboard input must be encoded as a single integer value; e.g. a character code
175 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must
176 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection,
177 | // i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
178 | //
179 | // You can encode other things, such as CONTROL or ALT, in additional bits, and
180 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example,
181 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN
182 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit,
183 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the
184 | // API below. The control keys will only match WM_KEYDOWN events because of the
185 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN
186 | // bit so it only decodes WM_CHAR events.
187 | //
188 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed
189 | // row of characters assuming they start on the i'th character--the width and
190 | // the height and the number of characters consumed. This allows this library
191 | // to traverse the entire layout incrementally. You need to compute word-wrapping
192 | // here.
193 | //
194 | // Each textfield keeps its own insert mode state, which is not how normal
195 | // applications work. To keep an app-wide insert mode, update/copy the
196 | // "insert_mode" field of STB_TexteditState before/after calling API functions.
197 | //
198 | // API
199 | //
200 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line)
201 | //
202 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
203 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
204 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
205 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
206 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key)
207 | //
208 | // Each of these functions potentially updates the string and updates the
209 | // state.
210 | //
211 | // initialize_state:
212 | // set the textedit state to a known good default state when initially
213 | // constructing the textedit.
214 | //
215 | // click:
216 | // call this with the mouse x,y on a mouse down; it will update the cursor
217 | // and reset the selection start/end to the cursor point. the x,y must
218 | // be relative to the text widget, with (0,0) being the top left.
219 | //
220 | // drag:
221 | // call this with the mouse x,y on a mouse drag/up; it will update the
222 | // cursor and the selection end point
223 | //
224 | // cut:
225 | // call this to delete the current selection; returns true if there was
226 | // one. you should FIRST copy the current selection to the system paste buffer.
227 | // (To copy, just copy the current selection out of the string yourself.)
228 | //
229 | // paste:
230 | // call this to paste text at the current cursor point or over the current
231 | // selection if there is one.
232 | //
233 | // key:
234 | // call this for keyboard inputs sent to the textfield. you can use it
235 | // for "key down" events or for "translated" key events. if you need to
236 | // do both (as in Win32), or distinguish Unicode characters from control
237 | // inputs, set a high bit to distinguish the two; then you can define the
238 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
239 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
240 | // clear.
241 | //
242 | // When rendering, you can read the cursor position and selection state from
243 | // the STB_TexteditState.
244 | //
245 | //
246 | // Notes:
247 | //
248 | // This is designed to be usable in IMGUI, so it allows for the possibility of
249 | // running in an IMGUI that has NOT cached the multi-line layout. For this
250 | // reason, it provides an interface that is compatible with computing the
251 | // layout incrementally--we try to make sure we make as few passes through
252 | // as possible. (For example, to locate the mouse pointer in the text, we
253 | // could define functions that return the X and Y positions of characters
254 | // and binary search Y and then X, but if we're doing dynamic layout this
255 | // will run the layout algorithm many times, so instead we manually search
256 | // forward in one pass. Similar logic applies to e.g. up-arrow and
257 | // down-arrow movement.)
258 | //
259 | // If it's run in a widget that *has* cached the layout, then this is less
260 | // efficient, but it's not horrible on modern computers. But you wouldn't
261 | // want to edit million-line files with it.
262 |
263 |
264 | ////////////////////////////////////////////////////////////////////////////
265 | ////////////////////////////////////////////////////////////////////////////
266 | ////
267 | //// Header-file mode
268 | ////
269 | ////
270 |
271 | #ifndef INCLUDE_STB_TEXTEDIT_H
272 | #define INCLUDE_STB_TEXTEDIT_H
273 |
274 | ////////////////////////////////////////////////////////////////////////
275 | //
276 | // STB_TexteditState
277 | //
278 | // Definition of STB_TexteditState which you should store
279 | // per-textfield; it includes cursor position, selection state,
280 | // and undo state.
281 | //
282 |
283 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT
284 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99
285 | #endif
286 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT
287 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999
288 | #endif
289 | #ifndef STB_TEXTEDIT_CHARTYPE
290 | #define STB_TEXTEDIT_CHARTYPE int
291 | #endif
292 | #ifndef STB_TEXTEDIT_POSITIONTYPE
293 | #define STB_TEXTEDIT_POSITIONTYPE int
294 | #endif
295 |
296 | typedef struct
297 | {
298 | // private data
299 | STB_TEXTEDIT_POSITIONTYPE where;
300 | short insert_length;
301 | short delete_length;
302 | short char_storage;
303 | } StbUndoRecord;
304 |
305 | typedef struct
306 | {
307 | // private data
308 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
309 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
310 | short undo_point, redo_point;
311 | short undo_char_point, redo_char_point;
312 | } StbUndoState;
313 |
314 | typedef struct
315 | {
316 | /////////////////////
317 | //
318 | // public data
319 | //
320 |
321 | int cursor;
322 | // position of the text cursor within the string
323 |
324 | int select_start; // selection start point
325 | int select_end;
326 | // selection start and end point in characters; if equal, no selection.
327 | // note that start may be less than or greater than end (e.g. when
328 | // dragging the mouse, start is where the initial click was, and you
329 | // can drag in either direction)
330 |
331 | unsigned char insert_mode;
332 | // each textfield keeps its own insert mode state. to keep an app-wide
333 | // insert mode, copy this value in/out of the app state
334 |
335 | /////////////////////
336 | //
337 | // private data
338 | //
339 | unsigned char cursor_at_end_of_line; // not implemented yet
340 | unsigned char initialized;
341 | unsigned char has_preferred_x;
342 | unsigned char single_line;
343 | unsigned char padding1, padding2, padding3;
344 | float preferred_x; // this determines where the cursor up/down tries to seek to along x
345 | StbUndoState undostate;
346 | } STB_TexteditState;
347 |
348 |
349 | ////////////////////////////////////////////////////////////////////////
350 | //
351 | // StbTexteditRow
352 | //
353 | // Result of layout query, used by stb_textedit to determine where
354 | // the text in each row is.
355 |
356 | // result of layout query
357 | typedef struct
358 | {
359 | float x0,x1; // starting x location, end x location (allows for align=right, etc)
360 | float baseline_y_delta; // position of baseline relative to previous row's baseline
361 | float ymin,ymax; // height of row above and below baseline
362 | int num_chars;
363 | } StbTexteditRow;
364 | #endif //INCLUDE_STB_TEXTEDIT_H
365 |
366 |
367 | ////////////////////////////////////////////////////////////////////////////
368 | ////////////////////////////////////////////////////////////////////////////
369 | ////
370 | //// Implementation mode
371 | ////
372 | ////
373 |
374 |
375 | // implementation isn't include-guarded, since it might have indirectly
376 | // included just the "header" portion
377 | #ifdef STB_TEXTEDIT_IMPLEMENTATION
378 |
379 | #ifndef STB_TEXTEDIT_memmove
380 | #include
381 | #define STB_TEXTEDIT_memmove memmove
382 | #endif
383 |
384 |
385 | /////////////////////////////////////////////////////////////////////////////
386 | //
387 | // Mouse input handling
388 | //
389 |
390 | // traverse the layout to locate the nearest character to a display position
391 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
392 | {
393 | StbTexteditRow r;
394 | int n = STB_TEXTEDIT_STRINGLEN(str);
395 | float base_y = 0, prev_x;
396 | int i=0, k;
397 |
398 | r.x0 = r.x1 = 0;
399 | r.ymin = r.ymax = 0;
400 | r.num_chars = 0;
401 |
402 | // search rows to find one that straddles 'y'
403 | while (i < n) {
404 | STB_TEXTEDIT_LAYOUTROW(&r, str, i);
405 | if (r.num_chars <= 0)
406 | return n;
407 |
408 | if (i==0 && y < base_y + r.ymin)
409 | return 0;
410 |
411 | if (y < base_y + r.ymax)
412 | break;
413 |
414 | i += r.num_chars;
415 | base_y += r.baseline_y_delta;
416 | }
417 |
418 | // below all text, return 'after' last character
419 | if (i >= n)
420 | return n;
421 |
422 | // check if it's before the beginning of the line
423 | if (x < r.x0)
424 | return i;
425 |
426 | // check if it's before the end of the line
427 | if (x < r.x1) {
428 | // search characters in row for one that straddles 'x'
429 | prev_x = r.x0;
430 | for (k=0; k < r.num_chars; ++k) {
431 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
432 | if (x < prev_x+w) {
433 | if (x < prev_x+w/2)
434 | return k+i;
435 | else
436 | return k+i+1;
437 | }
438 | prev_x += w;
439 | }
440 | // shouldn't happen, but if it does, fall through to end-of-line case
441 | }
442 |
443 | // if the last character is a newline, return that. otherwise return 'after' the last character
444 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
445 | return i+r.num_chars-1;
446 | else
447 | return i+r.num_chars;
448 | }
449 |
450 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection
451 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
452 | {
453 | state->cursor = stb_text_locate_coord(str, x, y);
454 | state->select_start = state->cursor;
455 | state->select_end = state->cursor;
456 | state->has_preferred_x = 0;
457 | }
458 |
459 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
460 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
461 | {
462 | int p = stb_text_locate_coord(str, x, y);
463 | if (state->select_start == state->select_end)
464 | state->select_start = state->cursor;
465 | state->cursor = state->select_end = p;
466 | }
467 |
468 | /////////////////////////////////////////////////////////////////////////////
469 | //
470 | // Keyboard input handling
471 | //
472 |
473 | // forward declarations
474 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
475 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
476 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
477 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
478 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
479 |
480 | typedef struct
481 | {
482 | float x,y; // position of n'th character
483 | float height; // height of line
484 | int first_char, length; // first char of row, and length
485 | int prev_first; // first char of previous row
486 | } StbFindState;
487 |
488 | // find the x/y location of a character, and remember info about the previous row in
489 | // case we get a move-up event (for page up, we'll have to rescan)
490 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line)
491 | {
492 | StbTexteditRow r;
493 | int prev_start = 0;
494 | int z = STB_TEXTEDIT_STRINGLEN(str);
495 | int i=0, first;
496 |
497 | if (n == z) {
498 | // if it's at the end, then find the last line -- simpler than trying to
499 | // explicitly handle this case in the regular code
500 | if (single_line) {
501 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
502 | find->y = 0;
503 | find->first_char = 0;
504 | find->length = z;
505 | find->height = r.ymax - r.ymin;
506 | find->x = r.x1;
507 | } else {
508 | find->y = 0;
509 | find->x = 0;
510 | find->height = 1;
511 | while (i < z) {
512 | STB_TEXTEDIT_LAYOUTROW(&r, str, i);
513 | prev_start = i;
514 | i += r.num_chars;
515 | }
516 | find->first_char = i;
517 | find->length = 0;
518 | find->prev_first = prev_start;
519 | }
520 | return;
521 | }
522 |
523 | // search rows to find the one that straddles character n
524 | find->y = 0;
525 |
526 | for(;;) {
527 | STB_TEXTEDIT_LAYOUTROW(&r, str, i);
528 | if (n < i + r.num_chars)
529 | break;
530 | prev_start = i;
531 | i += r.num_chars;
532 | find->y += r.baseline_y_delta;
533 | }
534 |
535 | find->first_char = first = i;
536 | find->length = r.num_chars;
537 | find->height = r.ymax - r.ymin;
538 | find->prev_first = prev_start;
539 |
540 | // now scan to find xpos
541 | find->x = r.x0;
542 | i = 0;
543 | for (i=0; first+i < n; ++i)
544 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
545 | }
546 |
547 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
548 |
549 | // make the selection/cursor state valid if client altered the string
550 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
551 | {
552 | int n = STB_TEXTEDIT_STRINGLEN(str);
553 | if (STB_TEXT_HAS_SELECTION(state)) {
554 | if (state->select_start > n) state->select_start = n;
555 | if (state->select_end > n) state->select_end = n;
556 | // if clamping forced them to be equal, move the cursor to match
557 | if (state->select_start == state->select_end)
558 | state->cursor = state->select_start;
559 | }
560 | if (state->cursor > n) state->cursor = n;
561 | }
562 |
563 | // delete characters while updating undo
564 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
565 | {
566 | stb_text_makeundo_delete(str, state, where, len);
567 | STB_TEXTEDIT_DELETECHARS(str, where, len);
568 | state->has_preferred_x = 0;
569 | }
570 |
571 | // delete the section
572 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
573 | {
574 | stb_textedit_clamp(str, state);
575 | if (STB_TEXT_HAS_SELECTION(state)) {
576 | if (state->select_start < state->select_end) {
577 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
578 | state->select_end = state->cursor = state->select_start;
579 | } else {
580 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
581 | state->select_start = state->cursor = state->select_end;
582 | }
583 | state->has_preferred_x = 0;
584 | }
585 | }
586 |
587 | // canoncialize the selection so start <= end
588 | static void stb_textedit_sortselection(STB_TexteditState *state)
589 | {
590 | if (state->select_end < state->select_start) {
591 | int temp = state->select_end;
592 | state->select_end = state->select_start;
593 | state->select_start = temp;
594 | }
595 | }
596 |
597 | // move cursor to first character of selection
598 | static void stb_textedit_move_to_first(STB_TexteditState *state)
599 | {
600 | if (STB_TEXT_HAS_SELECTION(state)) {
601 | stb_textedit_sortselection(state);
602 | state->cursor = state->select_start;
603 | state->select_end = state->select_start;
604 | state->has_preferred_x = 0;
605 | }
606 | }
607 |
608 | // move cursor to last character of selection
609 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
610 | {
611 | if (STB_TEXT_HAS_SELECTION(state)) {
612 | stb_textedit_sortselection(state);
613 | stb_textedit_clamp(str, state);
614 | state->cursor = state->select_end;
615 | state->select_start = state->select_end;
616 | state->has_preferred_x = 0;
617 | }
618 | }
619 |
620 | #ifdef STB_TEXTEDIT_IS_SPACE
621 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
622 | {
623 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
624 | }
625 |
626 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT
627 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
628 | {
629 | --c; // always move at least one character
630 | while( c >= 0 && !is_word_boundary( str, c ) )
631 | --c;
632 |
633 | if( c < 0 )
634 | c = 0;
635 |
636 | return c;
637 | }
638 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
639 | #endif
640 |
641 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT
642 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
643 | {
644 | const int len = STB_TEXTEDIT_STRINGLEN(str);
645 | ++c; // always move at least one character
646 | while( c < len && !is_word_boundary( str, c ) )
647 | ++c;
648 |
649 | if( c > len )
650 | c = len;
651 |
652 | return c;
653 | }
654 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
655 | #endif
656 |
657 | #endif
658 |
659 | // update selection and cursor to match each other
660 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
661 | {
662 | if (!STB_TEXT_HAS_SELECTION(state))
663 | state->select_start = state->select_end = state->cursor;
664 | else
665 | state->cursor = state->select_end;
666 | }
667 |
668 | // API cut: delete selection
669 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
670 | {
671 | if (STB_TEXT_HAS_SELECTION(state)) {
672 | stb_textedit_delete_selection(str,state); // implicity clamps
673 | state->has_preferred_x = 0;
674 | return 1;
675 | }
676 | return 0;
677 | }
678 |
679 | // API paste: replace existing selection with passed-in text
680 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
681 | {
682 | STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext;
683 | // if there's a selection, the paste should delete it
684 | stb_textedit_clamp(str, state);
685 | stb_textedit_delete_selection(str,state);
686 | // try to insert the characters
687 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
688 | stb_text_makeundo_insert(state, state->cursor, len);
689 | state->cursor += len;
690 | state->has_preferred_x = 0;
691 | return 1;
692 | }
693 | // remove the undo since we didn't actually insert the characters
694 | if (state->undostate.undo_point)
695 | --state->undostate.undo_point;
696 | return 0;
697 | }
698 |
699 | // API key: process a keyboard input
700 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key)
701 | {
702 | retry:
703 | switch (key) {
704 | default: {
705 | int c = STB_TEXTEDIT_KEYTOTEXT(key);
706 | if (c > 0) {
707 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
708 |
709 | // can't add newline in single-line mode
710 | if (c == '\n' && state->single_line)
711 | break;
712 |
713 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
714 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
715 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
716 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
717 | ++state->cursor;
718 | state->has_preferred_x = 0;
719 | }
720 | } else {
721 | stb_textedit_delete_selection(str,state); // implicity clamps
722 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
723 | stb_text_makeundo_insert(state, state->cursor, 1);
724 | ++state->cursor;
725 | state->has_preferred_x = 0;
726 | }
727 | }
728 | }
729 | break;
730 | }
731 |
732 | #ifdef STB_TEXTEDIT_K_INSERT
733 | case STB_TEXTEDIT_K_INSERT:
734 | state->insert_mode = !state->insert_mode;
735 | break;
736 | #endif
737 |
738 | case STB_TEXTEDIT_K_UNDO:
739 | stb_text_undo(str, state);
740 | state->has_preferred_x = 0;
741 | break;
742 |
743 | case STB_TEXTEDIT_K_REDO:
744 | stb_text_redo(str, state);
745 | state->has_preferred_x = 0;
746 | break;
747 |
748 | case STB_TEXTEDIT_K_LEFT:
749 | // if currently there's a selection, move cursor to start of selection
750 | if (STB_TEXT_HAS_SELECTION(state))
751 | stb_textedit_move_to_first(state);
752 | else
753 | if (state->cursor > 0)
754 | --state->cursor;
755 | state->has_preferred_x = 0;
756 | break;
757 |
758 | case STB_TEXTEDIT_K_RIGHT:
759 | // if currently there's a selection, move cursor to end of selection
760 | if (STB_TEXT_HAS_SELECTION(state))
761 | stb_textedit_move_to_last(str, state);
762 | else
763 | ++state->cursor;
764 | stb_textedit_clamp(str, state);
765 | state->has_preferred_x = 0;
766 | break;
767 |
768 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
769 | stb_textedit_clamp(str, state);
770 | stb_textedit_prep_selection_at_cursor(state);
771 | // move selection left
772 | if (state->select_end > 0)
773 | --state->select_end;
774 | state->cursor = state->select_end;
775 | state->has_preferred_x = 0;
776 | break;
777 |
778 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT
779 | case STB_TEXTEDIT_K_WORDLEFT:
780 | if (STB_TEXT_HAS_SELECTION(state))
781 | stb_textedit_move_to_first(state);
782 | else {
783 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
784 | stb_textedit_clamp( str, state );
785 | }
786 | break;
787 |
788 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
789 | if( !STB_TEXT_HAS_SELECTION( state ) )
790 | stb_textedit_prep_selection_at_cursor(state);
791 |
792 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
793 | state->select_end = state->cursor;
794 |
795 | stb_textedit_clamp( str, state );
796 | break;
797 | #endif
798 |
799 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT
800 | case STB_TEXTEDIT_K_WORDRIGHT:
801 | if (STB_TEXT_HAS_SELECTION(state))
802 | stb_textedit_move_to_last(str, state);
803 | else {
804 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
805 | stb_textedit_clamp( str, state );
806 | }
807 | break;
808 |
809 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
810 | if( !STB_TEXT_HAS_SELECTION( state ) )
811 | stb_textedit_prep_selection_at_cursor(state);
812 |
813 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
814 | state->select_end = state->cursor;
815 |
816 | stb_textedit_clamp( str, state );
817 | break;
818 | #endif
819 |
820 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
821 | stb_textedit_prep_selection_at_cursor(state);
822 | // move selection right
823 | ++state->select_end;
824 | stb_textedit_clamp(str, state);
825 | state->cursor = state->select_end;
826 | state->has_preferred_x = 0;
827 | break;
828 |
829 | case STB_TEXTEDIT_K_DOWN:
830 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: {
831 | StbFindState find;
832 | StbTexteditRow row;
833 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
834 |
835 | if (state->single_line) {
836 | // on windows, up&down in single-line behave like left&right
837 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
838 | goto retry;
839 | }
840 |
841 | if (sel)
842 | stb_textedit_prep_selection_at_cursor(state);
843 | else if (STB_TEXT_HAS_SELECTION(state))
844 | stb_textedit_move_to_last(str,state);
845 |
846 | // compute current position of cursor point
847 | stb_textedit_clamp(str, state);
848 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
849 |
850 | // now find character position down a row
851 | if (find.length) {
852 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
853 | float x;
854 | int start = find.first_char + find.length;
855 | state->cursor = start;
856 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
857 | x = row.x0;
858 | for (i=0; i < row.num_chars; ++i) {
859 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
860 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
861 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
862 | break;
863 | #endif
864 | x += dx;
865 | if (x > goal_x)
866 | break;
867 | ++state->cursor;
868 | }
869 | stb_textedit_clamp(str, state);
870 |
871 | state->has_preferred_x = 1;
872 | state->preferred_x = goal_x;
873 |
874 | if (sel)
875 | state->select_end = state->cursor;
876 | }
877 | break;
878 | }
879 |
880 | case STB_TEXTEDIT_K_UP:
881 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: {
882 | StbFindState find;
883 | StbTexteditRow row;
884 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
885 |
886 | if (state->single_line) {
887 | // on windows, up&down become left&right
888 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
889 | goto retry;
890 | }
891 |
892 | if (sel)
893 | stb_textedit_prep_selection_at_cursor(state);
894 | else if (STB_TEXT_HAS_SELECTION(state))
895 | stb_textedit_move_to_first(state);
896 |
897 | // compute current position of cursor point
898 | stb_textedit_clamp(str, state);
899 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
900 |
901 | // can only go up if there's a previous row
902 | if (find.prev_first != find.first_char) {
903 | // now find character position up a row
904 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
905 | float x;
906 | state->cursor = find.prev_first;
907 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
908 | x = row.x0;
909 | for (i=0; i < row.num_chars; ++i) {
910 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
911 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
912 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
913 | break;
914 | #endif
915 | x += dx;
916 | if (x > goal_x)
917 | break;
918 | ++state->cursor;
919 | }
920 | stb_textedit_clamp(str, state);
921 |
922 | state->has_preferred_x = 1;
923 | state->preferred_x = goal_x;
924 |
925 | if (sel)
926 | state->select_end = state->cursor;
927 | }
928 | break;
929 | }
930 |
931 | case STB_TEXTEDIT_K_DELETE:
932 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
933 | if (STB_TEXT_HAS_SELECTION(state))
934 | stb_textedit_delete_selection(str, state);
935 | else {
936 | int n = STB_TEXTEDIT_STRINGLEN(str);
937 | if (state->cursor < n)
938 | stb_textedit_delete(str, state, state->cursor, 1);
939 | }
940 | state->has_preferred_x = 0;
941 | break;
942 |
943 | case STB_TEXTEDIT_K_BACKSPACE:
944 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
945 | if (STB_TEXT_HAS_SELECTION(state))
946 | stb_textedit_delete_selection(str, state);
947 | else {
948 | stb_textedit_clamp(str, state);
949 | if (state->cursor > 0) {
950 | stb_textedit_delete(str, state, state->cursor-1, 1);
951 | --state->cursor;
952 | }
953 | }
954 | state->has_preferred_x = 0;
955 | break;
956 |
957 | #ifdef STB_TEXTEDIT_K_TEXTSTART2
958 | case STB_TEXTEDIT_K_TEXTSTART2:
959 | #endif
960 | case STB_TEXTEDIT_K_TEXTSTART:
961 | state->cursor = state->select_start = state->select_end = 0;
962 | state->has_preferred_x = 0;
963 | break;
964 |
965 | #ifdef STB_TEXTEDIT_K_TEXTEND2
966 | case STB_TEXTEDIT_K_TEXTEND2:
967 | #endif
968 | case STB_TEXTEDIT_K_TEXTEND:
969 | state->cursor = STB_TEXTEDIT_STRINGLEN(str);
970 | state->select_start = state->select_end = 0;
971 | state->has_preferred_x = 0;
972 | break;
973 |
974 | #ifdef STB_TEXTEDIT_K_TEXTSTART2
975 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
976 | #endif
977 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
978 | stb_textedit_prep_selection_at_cursor(state);
979 | state->cursor = state->select_end = 0;
980 | state->has_preferred_x = 0;
981 | break;
982 |
983 | #ifdef STB_TEXTEDIT_K_TEXTEND2
984 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
985 | #endif
986 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
987 | stb_textedit_prep_selection_at_cursor(state);
988 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
989 | state->has_preferred_x = 0;
990 | break;
991 |
992 |
993 | #ifdef STB_TEXTEDIT_K_LINESTART2
994 | case STB_TEXTEDIT_K_LINESTART2:
995 | #endif
996 | case STB_TEXTEDIT_K_LINESTART:
997 | stb_textedit_clamp(str, state);
998 | stb_textedit_move_to_first(state);
999 | if (state->single_line)
1000 | state->cursor = 0;
1001 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1002 | --state->cursor;
1003 | state->has_preferred_x = 0;
1004 | break;
1005 |
1006 | #ifdef STB_TEXTEDIT_K_LINEEND2
1007 | case STB_TEXTEDIT_K_LINEEND2:
1008 | #endif
1009 | case STB_TEXTEDIT_K_LINEEND: {
1010 | int n = STB_TEXTEDIT_STRINGLEN(str);
1011 | stb_textedit_clamp(str, state);
1012 | stb_textedit_move_to_first(state);
1013 | if (state->single_line)
1014 | state->cursor = n;
1015 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1016 | ++state->cursor;
1017 | state->has_preferred_x = 0;
1018 | break;
1019 | }
1020 |
1021 | #ifdef STB_TEXTEDIT_K_LINESTART2
1022 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1023 | #endif
1024 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1025 | stb_textedit_clamp(str, state);
1026 | stb_textedit_prep_selection_at_cursor(state);
1027 | if (state->single_line)
1028 | state->cursor = 0;
1029 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1030 | --state->cursor;
1031 | state->select_end = state->cursor;
1032 | state->has_preferred_x = 0;
1033 | break;
1034 |
1035 | #ifdef STB_TEXTEDIT_K_LINEEND2
1036 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1037 | #endif
1038 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1039 | int n = STB_TEXTEDIT_STRINGLEN(str);
1040 | stb_textedit_clamp(str, state);
1041 | stb_textedit_prep_selection_at_cursor(state);
1042 | if (state->single_line)
1043 | state->cursor = n;
1044 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1045 | ++state->cursor;
1046 | state->select_end = state->cursor;
1047 | state->has_preferred_x = 0;
1048 | break;
1049 | }
1050 |
1051 | // @TODO:
1052 | // STB_TEXTEDIT_K_PGUP - move cursor up a page
1053 | // STB_TEXTEDIT_K_PGDOWN - move cursor down a page
1054 | }
1055 | }
1056 |
1057 | /////////////////////////////////////////////////////////////////////////////
1058 | //
1059 | // Undo processing
1060 | //
1061 | // @OPTIMIZE: the undo/redo buffer should be circular
1062 |
1063 | static void stb_textedit_flush_redo(StbUndoState *state)
1064 | {
1065 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1066 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1067 | }
1068 |
1069 | // discard the oldest entry in the undo list
1070 | static void stb_textedit_discard_undo(StbUndoState *state)
1071 | {
1072 | if (state->undo_point > 0) {
1073 | // if the 0th undo state has characters, clean those up
1074 | if (state->undo_rec[0].char_storage >= 0) {
1075 | int n = state->undo_rec[0].insert_length, i;
1076 | // delete n characters from all other records
1077 | state->undo_char_point = state->undo_char_point - (short) n; // vsnet05
1078 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
1079 | for (i=0; i < state->undo_point; ++i)
1080 | if (state->undo_rec[i].char_storage >= 0)
1081 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it
1082 | }
1083 | --state->undo_point;
1084 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0])));
1085 | }
1086 | }
1087 |
1088 | // discard the oldest entry in the redo list--it's bad if this
1089 | // ever happens, but because undo & redo have to store the actual
1090 | // characters in different cases, the redo character buffer can
1091 | // fill up even though the undo buffer didn't
1092 | static void stb_textedit_discard_redo(StbUndoState *state)
1093 | {
1094 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
1095 |
1096 | if (state->redo_point <= k) {
1097 | // if the k'th undo state has characters, clean those up
1098 | if (state->undo_rec[k].char_storage >= 0) {
1099 | int n = state->undo_rec[k].insert_length, i;
1100 | // delete n characters from all other records
1101 | state->redo_char_point = state->redo_char_point + (short) n; // vsnet05
1102 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
1103 | for (i=state->redo_point; i < k; ++i)
1104 | if (state->undo_rec[i].char_storage >= 0)
1105 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05
1106 | }
1107 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point-1, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
1108 | ++state->redo_point;
1109 | }
1110 | }
1111 |
1112 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars)
1113 | {
1114 | // any time we create a new undo record, we discard redo
1115 | stb_textedit_flush_redo(state);
1116 |
1117 | // if we have no free records, we have to make room, by sliding the
1118 | // existing records down
1119 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1120 | stb_textedit_discard_undo(state);
1121 |
1122 | // if the characters to store won't possibly fit in the buffer, we can't undo
1123 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
1124 | state->undo_point = 0;
1125 | state->undo_char_point = 0;
1126 | return NULL;
1127 | }
1128 |
1129 | // if we don't have enough free characters in the buffer, we have to make room
1130 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
1131 | stb_textedit_discard_undo(state);
1132 |
1133 | return &state->undo_rec[state->undo_point++];
1134 | }
1135 |
1136 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
1137 | {
1138 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
1139 | if (r == NULL)
1140 | return NULL;
1141 |
1142 | r->where = pos;
1143 | r->insert_length = (short) insert_len;
1144 | r->delete_length = (short) delete_len;
1145 |
1146 | if (insert_len == 0) {
1147 | r->char_storage = -1;
1148 | return NULL;
1149 | } else {
1150 | r->char_storage = state->undo_char_point;
1151 | state->undo_char_point = state->undo_char_point + (short) insert_len;
1152 | return &state->undo_char[r->char_storage];
1153 | }
1154 | }
1155 |
1156 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
1157 | {
1158 | StbUndoState *s = &state->undostate;
1159 | StbUndoRecord u, *r;
1160 | if (s->undo_point == 0)
1161 | return;
1162 |
1163 | // we need to do two things: apply the undo record, and create a redo record
1164 | u = s->undo_rec[s->undo_point-1];
1165 | r = &s->undo_rec[s->redo_point-1];
1166 | r->char_storage = -1;
1167 |
1168 | r->insert_length = u.delete_length;
1169 | r->delete_length = u.insert_length;
1170 | r->where = u.where;
1171 |
1172 | if (u.delete_length) {
1173 | // if the undo record says to delete characters, then the redo record will
1174 | // need to re-insert the characters that get deleted, so we need to store
1175 | // them.
1176 |
1177 | // there are three cases:
1178 | // there's enough room to store the characters
1179 | // characters stored for *redoing* don't leave room for redo
1180 | // characters stored for *undoing* don't leave room for redo
1181 | // if the last is true, we have to bail
1182 |
1183 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
1184 | // the undo records take up too much character space; there's no space to store the redo characters
1185 | r->insert_length = 0;
1186 | } else {
1187 | int i;
1188 |
1189 | // there's definitely room to store the characters eventually
1190 | while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1191 | // there's currently not enough room, so discard a redo record
1192 | stb_textedit_discard_redo(s);
1193 | // should never happen:
1194 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1195 | return;
1196 | }
1197 | r = &s->undo_rec[s->redo_point-1];
1198 |
1199 | r->char_storage = s->redo_char_point - u.delete_length;
1200 | s->redo_char_point = s->redo_char_point - (short) u.delete_length;
1201 |
1202 | // now save the characters
1203 | for (i=0; i < u.delete_length; ++i)
1204 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1205 | }
1206 |
1207 | // now we can carry out the deletion
1208 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1209 | }
1210 |
1211 | // check type of recorded action:
1212 | if (u.insert_length) {
1213 | // easy case: was a deletion, so we need to insert n characters
1214 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1215 | s->undo_char_point -= u.insert_length;
1216 | }
1217 |
1218 | state->cursor = u.where + u.insert_length;
1219 |
1220 | s->undo_point--;
1221 | s->redo_point--;
1222 | }
1223 |
1224 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
1225 | {
1226 | StbUndoState *s = &state->undostate;
1227 | StbUndoRecord *u, r;
1228 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1229 | return;
1230 |
1231 | // we need to do two things: apply the redo record, and create an undo record
1232 | u = &s->undo_rec[s->undo_point];
1233 | r = s->undo_rec[s->redo_point];
1234 |
1235 | // we KNOW there must be room for the undo record, because the redo record
1236 | // was derived from an undo record
1237 |
1238 | u->delete_length = r.insert_length;
1239 | u->insert_length = r.delete_length;
1240 | u->where = r.where;
1241 | u->char_storage = -1;
1242 |
1243 | if (r.delete_length) {
1244 | // the redo record requires us to delete characters, so the undo record
1245 | // needs to store the characters
1246 |
1247 | if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1248 | u->insert_length = 0;
1249 | u->delete_length = 0;
1250 | } else {
1251 | int i;
1252 | u->char_storage = s->undo_char_point;
1253 | s->undo_char_point = s->undo_char_point + u->insert_length;
1254 |
1255 | // now save the characters
1256 | for (i=0; i < u->insert_length; ++i)
1257 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1258 | }
1259 |
1260 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1261 | }
1262 |
1263 | if (r.insert_length) {
1264 | // easy case: need to insert n characters
1265 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1266 | s->redo_char_point += r.insert_length;
1267 | }
1268 |
1269 | state->cursor = r.where + r.insert_length;
1270 |
1271 | s->undo_point++;
1272 | s->redo_point++;
1273 | }
1274 |
1275 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length)
1276 | {
1277 | stb_text_createundo(&state->undostate, where, 0, length);
1278 | }
1279 |
1280 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
1281 | {
1282 | int i;
1283 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
1284 | if (p) {
1285 | for (i=0; i < length; ++i)
1286 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1287 | }
1288 | }
1289 |
1290 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
1291 | {
1292 | int i;
1293 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1294 | if (p) {
1295 | for (i=0; i < old_length; ++i)
1296 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1297 | }
1298 | }
1299 |
1300 | // reset the state to default
1301 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line)
1302 | {
1303 | state->undostate.undo_point = 0;
1304 | state->undostate.undo_char_point = 0;
1305 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1306 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1307 | state->select_end = state->select_start = 0;
1308 | state->cursor = 0;
1309 | state->has_preferred_x = 0;
1310 | state->preferred_x = 0;
1311 | state->cursor_at_end_of_line = 0;
1312 | state->initialized = 1;
1313 | state->single_line = (unsigned char) is_single_line;
1314 | state->insert_mode = 0;
1315 | }
1316 |
1317 | // API initialize
1318 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line)
1319 | {
1320 | stb_textedit_clear_state(state, is_single_line);
1321 | }
1322 | #endif//STB_TEXTEDIT_IMPLEMENTATION
1323 |
--------------------------------------------------------------------------------
/imgui_dock.h:
--------------------------------------------------------------------------------
1 | // -*-c++-*-
2 | /*
3 | Copyright (c) 2017 Alberto Otero de la Roza
4 | , Robin Myhr , Isaac
5 | Visintainer , Richard Greaves , Ángel
6 | Martín Pendás and Víctor Luaña
7 | .
8 |
9 | critic2 is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or (at
12 | your option) any later version.
13 |
14 | critic2 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
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program. If not, see .
21 | */
22 | // Rewritten from: git@github.com:vassvik/imgui_docking_minimal.git
23 | // Original code by vassvik (?) released as public domain.
24 |
25 | // This code provides a collection of docking windows and containers
26 | // for the immediate-mode graphical user interface (ImGui) library
27 | // (https://github.com/ocornut/imgui) by Omar Cornut and
28 | // collaborators. Three components are implemented:
29 | //
30 | // 1. Docks - Behave like normal windows, but can attach themselves to
31 | // containers and root containers.
32 | //
33 | // 2. Containers - Windows that display the contents of docks attached
34 | // to them. Containers have a tab bar at the top that shows all
35 | // containers attached. At any time, one tab is active and the rest
36 | // are hidden. Very similar to how a browser window (e.g. chrome,
37 | // firefox) works.
38 | //
39 | // 3. Root containers - docks and containers can be attached to root
40 | // container windows. The window space of a root container is split
41 | // when a new window is added to it, depending on the position at
42 | // which it is dropped. Containers inside root containers keep track
43 | // of attached docks, and have an additional "lift grip" by which they
44 | // can be pulled out of the root container.
45 | //
46 | // Besides the attaching/detaching, all three components behave like
47 | // normal windows - they can be resized, auto-resized, moved,
48 | // collapsed, and closed. The usual flags (NoResize,
49 | // NoBringToFrontOnFocus,...) and placement commands
50 | // (SetNextWindowPos,...) work as well.
51 | //
52 | // The public interface contains the following:
53 | //
54 | // - The ImGui::Dock structure: docks, containers, and root containers
55 | // are instances of this class.
56 | //
57 | // - ImGui::RootContainer: create a root container and return a
58 | // pointer to the new Dock object.
59 | //
60 | // - ImGui::Container: create a container and return a pointer to the
61 | // new Dock object. Neither root containers nor containers need to
62 | // call an End() function (because no items are allowed inside them).
63 | //
64 | // - ImGui::BeginDock and ImGui::EndDock: the equivalent for docks to what
65 | // ImGui::Begin() and ImGui::End() are for windows. They open and
66 | // close a dock. If BeginDock returns true, interactive items can be
67 | // added to the dock. In addition, the argument oncedock allows
68 | // docking the dock to a container in the first pass. More convoluted
69 | // ways to attach docks and containers on initialization are possible
70 | // using the newDock and newDockRoot functions - an example will be
71 | // provided elsewhere.
72 | //
73 | // - ImGui::GetCurrentDock: when used beteween BeginDock and EndDock,
74 | // returns a pointer to the currently open dock. Otherwise, returns
75 | // null.
76 | //
77 | // - ImGui::ShutdownDock: deallocates memory for the dock hash
78 | // table. Should be run once docks are no longer needed, or at the end
79 | // of the program.
80 | //
81 | // Some notes:
82 | //
83 | // 1. Call RootContainer before any Container attached to it, and
84 | // Container before any BeginDock/EndDock attached to it. Doing it the
85 | // other way around works, but since root containers set the position
86 | // of containers, and containers of docks, it will result in a lag of
87 | // one or two frames when moving windows about.
88 | //
89 | // 2. Some widgets from imgui_widgets are used, so you will need that
90 | // file and its header to use docks.
91 | //
92 | // Have fun! -- Alberto
93 |
94 | #ifndef IMGUI_DOCK_H
95 | #define IMGUI_DOCK_H
96 |
97 | #include "imgui.h"
98 | #include "imgui_internal.h"
99 | #include
100 | #include
101 |
102 | namespace ImGui{
103 |
104 | typedef int DockFlags;
105 |
106 | struct Dock{
107 | enum Drop_ {Drop_None, Drop_Top, Drop_Right, Drop_Bottom, Drop_Left, Drop_Tab};
108 |
109 | // Enum for the type of docking windows
110 | enum Type_{Type_None,Type_Root,Type_Container,Type_Dock,Type_Horizontal,
111 | Type_Vertical};
112 | // Status of a single dock
113 | enum Status_{Status_None,Status_Open,Status_Collapsed,Status_Closed,
114 | Status_Dragged,Status_Docked};
115 | // Dock flags
116 | enum DockFlags_{
117 | DockFlags_NoLiftContainer = 1 << 0, // A container is not allowed to be lifted
118 | DockFlags_Transparent = 1 << 1, // This window is transparent (but still handles inputs)
119 | };
120 |
121 | char* label = nullptr; // dock and window label
122 | ImGuiWindow* window = nullptr; // associated window
123 | Type_ type = Type_None; // type of docking window
124 | Status_ status = Status_None; // status of the docking window
125 | ImVec2 pos = {}; // position of the window
126 | ImVec2 pos_saved = {}; // position of the window (before docking)
127 | ImVec2 size = {-1.f,-1.f}; // size of the window
128 | ImVec2 size_saved = {}; // saved size (before docking for dockable window)
129 | ImGuiWindowFlags flags = 0; // flags for the window
130 | ImGuiWindowFlags flags_saved = 0; // flags for the window (before docking)
131 | DockFlags dockflags = 0; // flags for this dock
132 | bool collapsed = false; // whether a docked window is collapsed
133 | bool collapsed_saved = false; // saved collapsed (before docking)
134 | ImRect tabbarrect = {}; // rectangle for the container tab bar
135 | float tabdz = 0.f; // z position for the end of the tab bar (container)
136 | ImGuiWindow* tabwin = nullptr; // pointer to the tab window (for cleaning up the window stack)
137 | ImVector tabsx = {}; // tab positions for container; sliders for h/v-container
138 | int splithint = 0; // hint to tell which bar should be removed when lifted (0 = any, +1 right/up, -1 left/down)
139 | ImVec2 splitweight = {1.f,1.f}; // relative weight of this dock - used to set the initial position of the bar in a h-v split
140 | bool hidden = false; // whether a docked window is hidden
141 | bool noborder = false; // flag if we pushed to have no border
142 | bool showingdrops = false; // true if we are showing the drop targets for this dock
143 | bool hoverable = true; // whether a window responds to being hovered
144 | std::list stack = {}; // stack of docks at this level
145 | Dock *currenttab = nullptr; // currently selected tab (container)
146 | Dock *parent = nullptr; // immediate dock to which this is dock
147 | Dock *root = nullptr; // root container to which this is docked
148 | bool *p_open = nullptr; // the calling routine open window bool
149 | bool control_window_this_frame = false; // the pos, size, etc. change window's attributes this frame
150 | int nchild_ = 0; // number of children (to generate labels in rootcontainer)
151 | int nchild = 0; // number of children (to count for the last dock in rootcontainer)
152 | bool automatic = false; // whether this dock was automatically generated in a rootcontainer
153 |
154 | Dock(){};
155 | ~Dock(){ MemFree(label);}
156 |
157 | // Is the mouse hovering the tab bar of this dock? (no rectangle clipping)
158 | bool IsMouseHoveringTabBar();
159 | // Is the mouse hovering the drop edges of a container? (no rectangle clipping)
160 | // Returns the edge id.
161 | Drop_ IsMouseHoveringEdge();
162 | // Returns true if the mouse is hovering the drop target when the container
163 | // is empty. (no rectangle clipping)
164 | bool IsMouseHoveringFull();
165 | // Get the nearest tab border in the tab when hovering a
166 | // container. Returns the tab number or -1 if the tab bar is not
167 | // hovered or there are no tabs.
168 | int getNearestTabBorder();
169 |
170 | // Show a drop targets on this window that covers the whole window.
171 | void showDropTargetFull();
172 | // Show the drop targets on this window's tab bar
173 | void showDropTargetOnTabBar();
174 | // Show the drop targets on the edge of the container. edge is the
175 | // id for the edge (1:top, 2:right, 3:bottom, 4:left).
176 | void showDropTargetEdge(Drop_ edge, bool active);
177 |
178 | // Find the integer index of dock dthis in the stack of this
179 | // container or h/v-container.
180 | int OpStack_Find(Dock *dthis);
181 | // Insert the dock dnew in the stack of this at position ithis (or
182 | // at the back if ithis == -1.
183 | void OpStack_Insert(Dock *dnew, int ithis=-1);
184 | // Replace the dock replaced with replacement in this dock's
185 | // stack. If erase, kill the replaced dock.
186 | void OpStack_Replace(Dock *replaced, Dock *replacement, bool erase);
187 | // Remove the dock dd from the stack of this container. If erase,
188 | // kill the dock as well.
189 | void OpStack_Remove(Dock *dd, bool erase);
190 |
191 | // Replace this dock (part of a root container tree) with a
192 | // horizontal (type==Type_Horizontal) or vertical
193 | // (type==Type_Vertical) container. The new container has the
194 | // current dock plus container dcont (if null, a new dcont is
195 | // allocated). The new container is placed before (before==true)
196 | // or after (false) the old one and the split uses weight for the
197 | // splitweight of the new container if dcont=null. Returns the new
198 | // container.
199 | Dock *OpRoot_ReplaceHV(Type_ type,bool before,Dock *dcont=nullptr,ImVec2 weight={1.f,1.f});
200 | // Add a new container (dcont) to the horizontal/vertical parent
201 | // of this dock. If !dcont, a new container is allocated. The new
202 | // container is placed before (before==true) or after (false) the
203 | // old one, and is returned by this function. The split uses
204 | // weight for the splitweight of the new container if dcont=null.
205 | Dock *OpRoot_AddToHV(bool before,Dock *dcont=nullptr,ImVec2 weight={1.f,1.f});
206 | // Fill an empty root container with at least one empty automatic
207 | // container.
208 | void OpRoot_FillEmpty();
209 |
210 | // Raise this dock's window to the top of the window stack.
211 | void raiseDock();
212 | // Raise this dock's window to the top of the window
213 | // stack. Or sink it if it is NoBringToFrontOnFocus.
214 | void raiseOrSinkDock();
215 | // Focus a container and its child and parent. Sets the move ID
216 | // and the active ID.
217 | void focusContainer();
218 | // Lift this container from its rootcontainer
219 | void liftContainer();
220 |
221 | // Add a new dock (dnew) to a container (this) at position ithis
222 | // in the tab bar, and make it the current tab. If ithis == -1,
223 | // add it to the end of the tab bar.
224 | void newDock(Dock *dnew, int ithis = -1);
225 | // Add a new dock to a root container, or a container docked to a
226 | // root container. If this is a root or h-v container, the new
227 | // dock is added to the last container in the tree (bottom
228 | // right). If the added dock is a container, just add it - if it
229 | // is a normal dock, create an automatic container for it. The
230 | // new dock is added at edge ithis of the container (1:top,
231 | // 2:right, 3:bottom, 4:left). edge = 5 is used to add to or
232 | // replace an automatic container in an empty root container.
233 | // Returns the new container.
234 | Dock *newDockRoot(Dock *dnew, Drop_ iedge);
235 |
236 | // Undock a container, restore its position, size, etc. flags, and
237 | // place it at the top or the bottom of the window stack. The
238 | // stack of the parent container is not modified.
239 | void unDock();
240 | // Clear all docked windows from a container
241 | void clearContainer();
242 | // Clear all docked windows from a root container
243 | void clearRootContainer();
244 |
245 | // Kill this automatic container if it is empty. If this
246 | // h/v-container is empty, convert it to a container. If it has
247 | // one window, kill it and connect its child to its parent.
248 | void killContainerMaybe();
249 |
250 | // Draw the tab bar of a container. On output, erased is true if a
251 | // tab in this container was closed.
252 | void drawTabBar(Dock **erased=nullptr);
253 | // Hide this dock docked to a container on an inactive tab.
254 | void hideTabWindow();
255 | // Show this dock docked to a container (dcont) on an active
256 | // tab. If noresize, do not show the resize grip.
257 | void showTabWindow(Dock *dcont, bool noresize);
258 | // Draw the contents of a container. If noresize, do not show the
259 | // resize grip. On output, erased is true if a tab in this
260 | // container was closed.
261 | void drawContainer(bool noresize, Dock **erased=nullptr);
262 |
263 | // Traverse the tree of this root container and return its minimum
264 | // size based on its contents. Recursive.
265 | void getMinSize(ImVec2 *minsize, ImVec2 *autosize);
266 | // Center all sliding bars in this root container.
267 | void resetRootContainerBars();
268 | // Sets the position of a sliding bar. The sliding bar is on edge
269 | // iedge (1:top, 2:right, 3:bottom, 4:left) of this container,
270 | // which is docked to a root container. xpos is the position of
271 | // the bar given as a fraction of the window size (between 0 and
272 | // 1).
273 | void setSlidingBarPosition(Drop_ iedge, float xpos);
274 | // Traverse the tree of this root container and draw all sliding
275 | // bars in it. Sets the tabsx vector containing the positions of
276 | // the bars. root is a pointer to the root container. Recursive.
277 | void drawRootContainerBars(Dock* root);
278 | // Traverse the tree of this root container and draw all
279 | // containers in it. Must be called after drawRootContainerBars to
280 | // have correct sliding bar positions. root is a pointer to the
281 | // root container. On output, lift contains a pointer to a
282 | // container to be lifted or null. erased points to the container
283 | // where one of the tabs was closed. count keeps count of the
284 | // number of docked windows in the root container. Recursive.
285 | void drawRootContainer(Dock* root, Dock **lift, Dock **erased, int *count = nullptr);
286 |
287 | // Sets the position of this dock/container in its detached
288 | // state. Useful when a dock/container is immediately attached in
289 | // the first pass and does not have the chance to save this
290 | // variable from the created window.
291 | void setDetachedDockPosition(float x, float y);
292 |
293 | // Sets the size of this dock/container in its detached
294 | // state. Useful when a dock/container is immediately attached in
295 | // the first pass and does not have the chance to save this
296 | // variable from the created window.
297 | void setDetachedDockSize(float x, float y);
298 |
299 | // Set the h-v split weight for this dock.
300 | void setSplitWeight(float wx,float wy);
301 |
302 | // Close a dock window. This function is used to kill a dock
303 | // externally. Unlike normal ImGui windows, making p_open false is
304 | // not enough if the window is docked, because the container has to
305 | // be modified, too. Therefore, CloseDock() should always be used
306 | // when setting p_open = false.
307 | void closeDock();
308 | }; // struct Dock
309 |
310 | // Create a root container with the given label. If p_open, with a
311 | // close button (close status as *p_open). Extra window flags are
312 | // passed to the container window. Dock flags can also be passed
313 | // (see above). Returns a pointer to the root container dock
314 | // object. Root containers can hold containers and docks.
315 | Dock *RootContainer(const char* label, bool* p_open=nullptr, ImGuiWindowFlags extra_flags=0, DockFlags dock_flags=0);
316 |
317 | // Create a container with the given label. If p_open, with a close
318 | // button (close status as *p_open). Extra window flags are passed
319 | // to the container window. Dock flags can also be passed (see
320 | // above). Returns a pointer to the container dock
321 | // object. Containers contain docks and can be docked to root
322 | // containers.
323 | Dock *Container(const char* label, bool* p_open=nullptr, ImGuiWindowFlags extra_flags=0, DockFlags dock_flags=0);
324 |
325 | // Create/end a dock window. If p_open, with a close button. If
326 | // p_open, with a close button (close status as *p_open). Extra
327 | // window flags are passed to the window. Dock flags can also be
328 | // passed (see above). If a pointer to a container is passed in
329 | // oncedock, dock to that container in the first pass. Returns true
330 | // if the window is open and accepts items (same as ImGui's
331 | // Begin). The EndDock() function needs to be used after all items
332 | // have been added. See closeDock() note above for how to set
333 | // p_open externally to close a dock.
334 | bool BeginDock(const char* label, bool* p_open=nullptr, ImGuiWindowFlags extra_flags=0,
335 | DockFlags dock_flags=0, Dock *oncedock=nullptr);
336 | void EndDock();
337 |
338 | // GetCurrentDock() gives the pointer to the current open dock (same
339 | // as GetCurrentWindow(), but for docks). Must appear between
340 | // BeginDock and EndDock. Returns null if no dock is open.
341 | Dock *GetCurrentDock();
342 |
343 | // Free the memory occupied dock hash tables.
344 | void ShutdownDock();
345 |
346 | // Print information about the current known docks. For debug purposes.
347 | void PrintDock__();
348 |
349 | } // namespace ImGui
350 | #endif
351 |
--------------------------------------------------------------------------------
/imgui_widgets.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017 Alberto Otero de la Roza
3 | , Robin Myhr , Isaac
4 | Visintainer , Richard Greaves , Ángel
5 | Martín Pendás and Víctor Luaña
6 | .
7 |
8 | critic2 is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or (at
11 | your option) any later version.
12 |
13 | critic2 is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | #include "imgui_widgets.h"
23 | #include "imgui.h"
24 | #include "imgui_internal.h"
25 |
26 | #include
27 | #include
28 |
29 | using namespace ImGui;
30 |
31 | // Tooltip variables and behavior //
32 | // Variables:
33 | // - tooltip_shownid: ID for the tooltip element shown.
34 | // - tooltip_hoveredid: ID for the tooltip element hovered last frame.
35 | // - tooltip_thisframe: saves the current frame to detect when
36 | // AttachTooltip is called for the first time.
37 | // - tooltip_washovered: set to true if any AttachTooltip element
38 | // has been hovered in the last frame.
39 | // - tooltip_time: the last time when no item was hovered.
40 | // - tooltip_lastactive - the last time when a tooltip was shown.
41 | // How it works:
42 | // The tooltip is shown if:
43 | // - The mouse hovers over a single tooltip element for longer than
44 | // delay, which is passed as a function argument.
45 | // - The mouse hovers over a tooltip element and it was already
46 | // showing a tooltip from a different element. In this case,
47 | // there is no delay.
48 | // - The mouse hovers over a tooltip element, then hovers none for a
49 | // period of time less than delay, then overs over a new tooltip
50 | // element. In this case, the delay is calculated as the difference
51 | // between the time the mouse hovered over the new tooltip element
52 | // (tooltip_time) and the time the mouse left the previous tooltip
53 | // element (tooltip_lastactive), with a maximum equal to
54 | // delay. Thus, the delay is equal to the time the mouse spent
55 | // outside any tooltip elment.
56 | static ImGuiID tooltip_shownid = 0;
57 | static ImGuiID tooltip_hoveredid = 0;
58 | static int tooltip_thisframe = -1;
59 | static bool tooltip_washovered = false;
60 | static float tooltip_time = 0.f;
61 | static float tooltip_lastactive = 0.f;
62 |
63 | // Variable for the widget styles
64 | ImGuiStyleWidgets_ ImGuiStyleWidgets;
65 |
66 | // Function definitions //
67 |
68 | bool ImGui::IsMouseHoveringConvexPoly(const ImVec2* points, const int num_points){
69 | ImGuiContext& g = *GImGui;
70 |
71 | float p0[num_points][2];
72 |
73 | // differences
74 | for (int i = 0; i < num_points; i++){
75 | p0[i][0] = points[i].x - g.IO.MousePos.x;
76 | p0[i][1] = points[i].y - g.IO.MousePos.y;
77 | }
78 |
79 | // first sign
80 | float a0 = p0[0][0] * p0[num_points-1][1] - p0[num_points-1][0] * p0[0][1];
81 |
82 | // compare to all other signs
83 | for (int i = 0; i < num_points-1; i++){
84 | float a = p0[i+1][0] * p0[i][1] - p0[i][0] * p0[i+1][1];
85 | if (a * a0 < 0.f)
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 |
92 | void ImGui::SlidingBar(const char *label, ImGuiWindow* window, ImVec2 *pos,
93 | ImVec2 size, float minx, float maxx, int direction){
94 | ImDrawList* dl = window->DrawList;
95 | ImGuiContext *g = GetCurrentContext();
96 | bool hovered, held;
97 | const ImU32 color = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_Slidingbar]);
98 | const ImU32 coloractive = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_SlidingbarActive]);
99 | const ImU32 colorhovered = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_SlidingbarHovered]);
100 |
101 | const ImRect slidingrect(*pos,*pos+size);
102 | const ImGuiID slidingid = window->GetID(label);
103 | ButtonBehavior(slidingrect, slidingid, &hovered, &held);
104 |
105 | if (hovered || held){
106 | if (direction == 1)
107 | SetMouseCursor(ImGuiMouseCursor_ResizeEW);
108 | else
109 | SetMouseCursor(ImGuiMouseCursor_ResizeNS);
110 | }
111 |
112 | if (held){
113 | if (direction == 1)
114 | pos->x = max(min(g->IO.MousePos.x - 0.5f * size.x,maxx),minx);
115 | else
116 | pos->y = max(min(g->IO.MousePos.y - 0.5f * size.y,maxx),minx);
117 | }
118 |
119 | // draw the rectangle
120 | dl->PushClipRectFullScreen();
121 | dl->AddRectFilled(slidingrect.GetTL(),slidingrect.GetBR(),
122 | held?coloractive:(hovered?colorhovered:color),
123 | g->Style.ScrollbarRounding);
124 | dl->PopClipRect();
125 | }
126 |
127 | bool ImGui::ButtonWithX(const char* label, const ImVec2& size, bool activetab,
128 | bool *p_open, bool *dragged, bool *dclicked, float alphamul /*=1.f*/){
129 | ImGuiContext *g = GetCurrentContext();
130 | const float crossz = round(0.3 * g->FontSize);
131 | const float crosswidth = 3.5f * crossz + 6;
132 | const float mintabwidth = 2 * crosswidth + 1;
133 |
134 | const ImU32 colorxfg = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXFg]);
135 | const ImU32 colorxfg_hovered = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXFgHovered]);
136 | const ImU32 colorxfg_pressed = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXFgActive]);
137 | const ImU32 colorxbg = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXBg]);
138 | const ImU32 colorxbg_hovered = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXBgHovered]);
139 | const ImU32 colorxbg_pressed = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabXBgActive]);
140 | ImU32 color = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_Tab]);
141 | ImU32 color_active = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabActive]);
142 | ImU32 color_pressed = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabPressed]);
143 | ImU32 color_hovered = GetColorU32(ImGuiStyleWidgets.Colors[ImGuiColWidgets_TabHovered]);
144 |
145 | // size of the main button
146 | ImVec2 mainsize = size;
147 | if (p_open && size.x >= mintabwidth)
148 | mainsize.x -= crosswidth;
149 |
150 | // main button
151 | bool clicked = InvisibleButton(label, mainsize);
152 |
153 | // some positions and other variables
154 | bool hovered = IsItemHovered();
155 | ImVec2 pos0 = GetItemRectMin();
156 | ImVec2 pos1s = GetItemRectMax();
157 |
158 | // set the output flags for the main button
159 | bool pressed = IsItemActive() && IsMouseDown(0);
160 | *dragged = IsItemActive() && IsMouseDragging();
161 | *dclicked = IsItemActive() && IsMouseDoubleClicked(0);
162 |
163 | // draw the close button, if this window can be closed
164 | ImVec2 center;
165 | bool xhovered = false, xpressed = false;
166 | if (p_open && size.x >= mintabwidth){
167 | // draw the close button itself
168 | SameLine();
169 | char tmp2[strlen(label)+6];
170 | ImFormatString(tmp2,IM_ARRAYSIZE(tmp2),"%s__x__",label);
171 | ImVec2 smallsize(crosswidth, size.y);
172 |
173 | // cross button
174 | *p_open = !(InvisibleButton(tmp2, smallsize));
175 |
176 | // update output flags and variables for drawing
177 | *dragged = *dragged | (p_open && IsItemActive() && IsMouseDragging());
178 | xhovered = IsItemHovered();
179 | hovered |= xhovered;
180 | xpressed = IsItemActive() && IsMouseDown(0);
181 | center = ((GetItemRectMin() + GetItemRectMax()) * 0.5f);
182 | }
183 | ImVec2 pos1 = GetItemRectMax();
184 |
185 | // rectangle and text
186 | ImDrawList* drawl = GetWindowDrawList();
187 | const char* text_end = FindRenderedTextEnd(label);
188 | ImVec2 text_size = CalcTextSize(label,text_end,true,false);
189 | ImRect clip_rect = ImRect(pos0,pos1s);
190 | drawl->AddRectFilled(pos0,pos1,activetab? color_active:
191 | pressed? color_pressed:
192 | hovered? color_hovered:
193 | color,ImGuiStyleWidgets.TabRounding,ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_TopRight);
194 |
195 | if (ImGuiStyleWidgets.TabBorderSize > 0.0f)
196 | drawl->AddRect(pos0,pos1,GetColorU32(g->Style.Colors[ImGuiColWidgets_TabBorder]),
197 | ImGuiStyleWidgets.TabRounding,ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_TopRight,1.0f);
198 | RenderTextClipped(pos0,pos1s,label,text_end,&text_size, ImVec2(0.5f,0.5f), &clip_rect);
199 |
200 | // draw the "x"
201 | if (p_open && size.x >= mintabwidth){
202 | drawl->AddCircleFilled(center,crossz * sqrt(2.f) * 1.25f,
203 | xpressed?colorxbg_pressed:
204 | xhovered?colorxbg_hovered:
205 | colorxbg,36);
206 | drawl->AddLine(center+ImVec2(-crossz,-crossz), center+ImVec2(crossz,crossz),
207 | xpressed?colorxfg_pressed:
208 | xhovered?colorxfg_hovered:
209 | colorxfg);
210 | drawl->AddLine(center+ImVec2( crossz,-crossz), center+ImVec2(-crossz,crossz),
211 | xpressed?colorxfg_pressed:
212 | xhovered?colorxfg_hovered:
213 | colorxfg);
214 | }
215 |
216 | return clicked;
217 | }
218 |
219 | void ImGui::ResizeGripOther(const char *label, ImGuiWindow* window, ImGuiWindow* cwindow, bool *dclicked/*=nullptr*/){
220 | static bool first = true;
221 | if (dclicked) *dclicked = false;
222 |
223 | static ImVec2 pos_orig = {};
224 | static ImVec2 size_orig = {};
225 | static ImVec2 csize_orig = {};
226 | ImGuiContext *g = GetCurrentContext();
227 | const ImVec2 br = window->Rect().GetBR();
228 | ImDrawList* dl = window->DrawList;
229 | const float resize_corner_size = ImMax(g->FontSize * 1.35f, g->Style.WindowRounding + 1.0f + g->FontSize * 0.2f);
230 | const ImRect resize_rect(br - ImVec2(resize_corner_size * 0.75f, resize_corner_size * 0.75f), br);
231 | char tmp[strlen(label)+15];
232 | ImFormatString(tmp,IM_ARRAYSIZE(tmp),"%s__resize__",label);
233 | const ImGuiID resize_id = window->GetID(tmp);
234 |
235 | // no clipping; save previous clipping
236 | ImRect saverect = window->ClipRect;
237 | window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
238 | dl->PushClipRectFullScreen();
239 |
240 | // button behavior
241 | bool hovered, held;
242 | ButtonBehavior(resize_rect, resize_id, &hovered, &held, ImGuiButtonFlags_FlattenChilds);
243 |
244 | // update the static flags
245 | if (held){
246 | if (first) {
247 | pos_orig = window->Pos;
248 | size_orig = window->SizeFull;
249 | csize_orig = cwindow->SizeFull;
250 | }
251 | first = false;
252 | } else {
253 | first = true;
254 | }
255 |
256 | // mouse cursor
257 | if (hovered || held)
258 | g->MouseCursor = ImGuiMouseCursor_ResizeNWSE;
259 |
260 | // apply the size change
261 | if (g->HoveredWindow == window && held && g->IO.MouseDoubleClicked[0]){
262 | if (dclicked) *dclicked = true;
263 | ImVec2 size_auto_fit = ImClamp(cwindow->SizeContents + cwindow->WindowPadding, g->Style.WindowMinSize,
264 | ImMax(g->Style.WindowMinSize, g->IO.DisplaySize - g->Style.DisplaySafeAreaPadding));
265 |
266 | cwindow->SizeFull = size_auto_fit;
267 | ClearActiveID();
268 | } else if (held)
269 | cwindow->SizeFull = csize_orig + (g->IO.MousePos - g->ActiveIdClickOffset + resize_rect.GetSize() - pos_orig) - size_orig;
270 | cwindow->Size = cwindow->SizeFull;
271 |
272 | // resize grip (from imgui.cpp)
273 | ImU32 resize_col = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
274 | dl->PathLineTo(br + ImVec2(-resize_corner_size, -window->WindowBorderSize));
275 | dl->PathLineTo(br + ImVec2(-window->WindowBorderSize, -resize_corner_size));
276 | dl->PathArcToFast(ImVec2(br.x - g->Style.WindowRounding - window->WindowBorderSize, br.y - g->Style.WindowRounding - window->WindowBorderSize), g->Style.WindowRounding, 0, 3);
277 | dl->PathFillConvex(resize_col);
278 | dl->PopClipRect();
279 | window->ClipRect = saverect;
280 | }
281 |
282 | bool ImGui::LiftGrip(const char *label, ImGuiWindow* window){
283 | ImGuiContext *g = GetCurrentContext();
284 | const ImVec2 bl = window->Rect().GetBL();
285 | ImDrawList* dl = window->DrawList;
286 | const float lift_corner_size = ImMax(g->FontSize * 1.35f, g->Style.WindowRounding + 1.0f + g->FontSize * 0.2f);
287 | const ImRect lift_rect(bl - ImVec2(0.f, lift_corner_size * 0.75f), bl + ImVec2(lift_corner_size * 0.75f, 0.f));
288 | char tmp[strlen(label)+15];
289 | ImFormatString(tmp,IM_ARRAYSIZE(tmp),"%s__lift__",label);
290 | const ImGuiID lift_id = window->GetID(tmp);
291 |
292 | // no clipping; save previous clipping
293 | ImRect saverect = window->ClipRect;
294 | window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
295 | dl->PushClipRectFullScreen();
296 |
297 | // button behavior
298 | bool hovered, held;
299 | ButtonBehavior(lift_rect, lift_id, &hovered, &held, ImGuiButtonFlags_FlattenChilds);
300 |
301 | // lift grip (from imgui.cpp's resize grip)
302 | ImU32 lift_col = GetColorU32(held?ImGuiStyleWidgets.Colors[ImGuiColWidgets_LiftGripActive]:
303 | hovered?ImGuiStyleWidgets.Colors[ImGuiColWidgets_LiftGripHovered]:
304 | ImGuiStyleWidgets.Colors[ImGuiColWidgets_LiftGrip]);
305 | dl->PathLineTo(bl + ImVec2(window->WindowBorderSize, -lift_corner_size));
306 | dl->PathLineTo(bl + ImVec2(lift_corner_size, -window->WindowBorderSize));
307 | dl->PathArcToFast(ImVec2(bl.x + g->Style.WindowRounding + window->WindowBorderSize, bl.y - g->Style.WindowRounding - window->WindowBorderSize), g->Style.WindowRounding, 3, 6);
308 | dl->PathFillConvex(lift_col);
309 | dl->PopClipRect();
310 | window->ClipRect = saverect;
311 |
312 | return held && IsMouseDragging();
313 | }
314 |
315 | bool ImGui::ImageInteractive(ImTextureID texture, float a, bool *hover, ImRect *vrect){
316 | ImGuiWindow *win = GetCurrentWindow();
317 | if (win->SkipItems)
318 | return false;
319 | ImGuiContext *g = GetCurrentContext();
320 |
321 | PushID((void *)texture);
322 | const ImGuiID id = win->GetID("#imageinteractive");
323 | PopID();
324 |
325 | vrect->Min = win->DC.CursorPos;
326 | vrect->Max = win->DC.CursorPos + win->ContentsRegionRect.Max - (win->DC.CursorPos - win->Pos + ImVec2(1.f,1.f));
327 |
328 | if (!ItemAdd(*vrect, id))
329 | return false;
330 |
331 | float x = vrect->Max.x - vrect->Min.x;
332 | float y = vrect->Max.y - vrect->Min.y;
333 | float xratio = x/fmax(x,y);
334 | float yratio = y/fmax(x,y);
335 | float rx = 0.5f * (1.f - xratio) * a;
336 | float ry = 0.5f * (1.f - yratio) * a;
337 |
338 | bool held;
339 | bool pressed = ButtonBehavior(*vrect, id, hover, &held);
340 | win->DrawList->AddImage(texture,vrect->Min,vrect->Max,ImVec2(rx, a - ry),ImVec2(a - rx, ry));
341 | return true;
342 | }
343 |
344 | bool ImGui::InvisibleButtonEx(const char* str_id, const ImVec2& size_arg, bool* hovered, bool *held){
345 | ImGuiWindow* window = GetCurrentWindow();
346 | if (window->SkipItems)
347 | return false;
348 |
349 | const ImGuiID id = window->GetID(str_id);
350 | ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
351 | const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
352 | ItemSize(bb);
353 | if (!ItemAdd(bb, id))
354 | return false;
355 |
356 | bool pressed = ButtonBehavior(bb, id, hovered, held);
357 |
358 | return pressed;
359 | }
360 |
361 | void ImGui::AttachTooltip(const char* desc, float delay, float maxwidth, ImFont* font){
362 | ImGuiContext *g = GetCurrentContext();
363 | ImGuiID id = g->CurrentWindow->DC.LastItemId;
364 | float time = GetTime();
365 | int thisframe = GetFrameCount();
366 |
367 | if (thisframe != tooltip_thisframe){
368 | // run once every frame, in the first call
369 | if (!tooltip_washovered){
370 | tooltip_time = time;
371 | tooltip_shownid = 0;
372 | tooltip_hoveredid = 0;
373 | }
374 | tooltip_thisframe = thisframe;
375 | tooltip_washovered = false;
376 | }
377 |
378 | if (g->HoveredId == id){
379 | // If no tooltip is being shown and the mouse moves from one tooltip element
380 | // to another, this is the same as if it moved from a zone without any
381 | // tooltip elements.
382 | if (id != tooltip_hoveredid && tooltip_shownid == 0)
383 | tooltip_time = time;
384 |
385 | if (tooltip_lastactive != 0.f)
386 | delay = fmin(delay,fmax(tooltip_time - tooltip_lastactive,0.f));
387 |
388 | tooltip_washovered = true;
389 | tooltip_hoveredid = id;
390 |
391 | if (time - tooltip_time > delay){
392 | tooltip_shownid = id;
393 | tooltip_lastactive = time;
394 | BeginTooltip();
395 | PushTextWrapPos(maxwidth);
396 | PushFont(font);
397 | TextUnformatted(desc);
398 | PopFont();
399 | PopTextWrapPos();
400 | EndTooltip();
401 | }
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/imgui_widgets.h:
--------------------------------------------------------------------------------
1 | // -*-c++-*-
2 | /*
3 | Copyright (c) 2017 Alberto Otero de la Roza
4 | , Robin Myhr , Isaac
5 | Visintainer , Richard Greaves , Ángel
6 | Martín Pendás and Víctor Luaña
7 | .
8 |
9 | critic2 is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or (at
12 | your option) any later version.
13 |
14 | critic2 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
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | // Several widgets independent from each other are provided by this
24 | // file. See below for a description.
25 |
26 | #ifndef IMGUI_WIDGETS_H
27 | #define IMGUI_WIDGETS_H
28 |
29 | #include "imgui_widgets.h"
30 | #include "imgui.h"
31 | #include "imgui_internal.h"
32 |
33 | using namespace std;
34 |
35 | // Helper functions
36 | static inline ImVec2 operator+(ImVec2 lhs, ImVec2 rhs) {
37 | return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y);
38 | }
39 | static inline ImVec2 operator-(ImVec2 lhs, ImVec2 rhs) {
40 | return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y);
41 | }
42 | static inline ImVec2 operator*(ImVec2 lhs, float rhs) {
43 | return ImVec2(lhs.x*rhs, lhs.y*rhs);
44 | }
45 | static inline ImVec4 OpaqueColor(ImGuiCol_ color, float newalpha){
46 | ImGuiContext *g = ImGui::GetCurrentContext();
47 | ImVec4 col = g->Style.Colors[color];
48 | col.w = newalpha;
49 | return col;
50 | }
51 | static inline ImVec4 TransparentColor(ImGuiCol_ color){
52 | const float small_alpha = 1e-15;
53 | ImGuiContext *g = ImGui::GetCurrentContext();
54 | ImVec4 col = g->Style.Colors[color];
55 | col.w = small_alpha;
56 | return col;
57 | }
58 |
59 | // Colors for the widgets
60 | enum ImGuiColWidgets_ {
61 | ImGuiColWidgets_Slidingbar,
62 | ImGuiColWidgets_SlidingbarHovered,
63 | ImGuiColWidgets_SlidingbarActive,
64 | ImGuiColWidgets_Tab,
65 | ImGuiColWidgets_TabHovered,
66 | ImGuiColWidgets_TabPressed,
67 | ImGuiColWidgets_TabActive,
68 | ImGuiColWidgets_TabXFg,
69 | ImGuiColWidgets_TabXFgHovered,
70 | ImGuiColWidgets_TabXFgActive,
71 | ImGuiColWidgets_TabXBg,
72 | ImGuiColWidgets_TabXBgHovered,
73 | ImGuiColWidgets_TabXBgActive,
74 | ImGuiColWidgets_TabBorder,
75 | ImGuiColWidgets_LiftGrip,
76 | ImGuiColWidgets_LiftGripHovered,
77 | ImGuiColWidgets_LiftGripActive,
78 | ImGuiColWidgets_DropTarget,
79 | ImGuiColWidgets_DropTargetActive,
80 | ImGuiColWidgets_COUNT,
81 | };
82 |
83 | // Style for the widgets
84 | struct ImGuiStyleWidgets_ {
85 | ImVec4 Colors[ImGuiColWidgets_COUNT];
86 | float TabRounding;
87 | float TabBorderSize;
88 | float DropTargetLooseness;
89 | float DropTargetMinsizeEdge;
90 | float DropTargetMaxsizeEdge;
91 | float DropTargetEdgeFraction;
92 | float DropTargetFullFraction;
93 | float TabHeight;
94 | float TabMaxWidth;
95 | float CascadeIncrement;
96 | float SlidingBarWidth;
97 |
98 | void DefaultStyle(){
99 | TabRounding = 7.0f;
100 | TabBorderSize = 0.0f;
101 | DropTargetLooseness = 4.0f;
102 | DropTargetMinsizeEdge = 20.f;
103 | DropTargetMaxsizeEdge = 20.f;
104 | DropTargetEdgeFraction = 0.1f;
105 | DropTargetFullFraction = 0.4f;
106 | TabHeight = 19.0f;
107 | TabMaxWidth = 100.f;
108 | CascadeIncrement = 25.f;
109 | SlidingBarWidth = 4.f;
110 | }
111 |
112 | void DefaultColors(){
113 | Colors[ImGuiColWidgets_Slidingbar] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
114 | Colors[ImGuiColWidgets_SlidingbarHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
115 | Colors[ImGuiColWidgets_SlidingbarActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
116 | Colors[ImGuiColWidgets_Tab] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
117 | Colors[ImGuiColWidgets_TabHovered] = ImVec4(0.45f, 0.45f, 0.90f, 1.00f);
118 | Colors[ImGuiColWidgets_TabPressed] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
119 | Colors[ImGuiColWidgets_TabActive] = ImVec4(0.53f, 0.53f, 0.87f, 1.00f);
120 | Colors[ImGuiColWidgets_TabXFg] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
121 | Colors[ImGuiColWidgets_TabXFgHovered] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
122 | Colors[ImGuiColWidgets_TabXFgActive] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
123 | Colors[ImGuiColWidgets_TabXBg] = ImVec4(0.80f, 0.20f, 0.00f, 0.00f);
124 | Colors[ImGuiColWidgets_TabXBgHovered] = ImVec4(0.80f, 0.20f, 0.00f, 1.00f);
125 | Colors[ImGuiColWidgets_TabXBgActive] = ImVec4(0.60f, 0.20f, 0.00f, 1.00f);
126 | Colors[ImGuiColWidgets_TabBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
127 | Colors[ImGuiColWidgets_LiftGrip] = ImVec4(0.60f, 0.20f, 0.00f, 1.00f);
128 | Colors[ImGuiColWidgets_LiftGripHovered] = ImVec4(0.80f, 0.40f, 0.20f, 1.00f);
129 | Colors[ImGuiColWidgets_LiftGripActive] = ImVec4(1.00f, 0.40f, 0.20f, 1.00f);
130 | Colors[ImGuiColWidgets_DropTarget] = ImVec4(0.43f, 0.43f, 0.43f, 0.43f);
131 | Colors[ImGuiColWidgets_DropTargetActive] = ImVec4(0.80f, 0.80f, 0.80f, 0.80f);
132 | }
133 |
134 | // gettabheight gettabwidth getslidingbarwidth ...
135 | ImGuiStyleWidgets_(){
136 | DefaultStyle();
137 | DefaultColors();
138 | };
139 | };
140 | extern ImGuiStyleWidgets_ ImGuiStyleWidgets;
141 |
142 | // Widgets added to ImGui
143 | namespace ImGui{
144 | // Returns true if mouse is hovering the inside of a convex
145 | // polygon.
146 | bool IsMouseHoveringConvexPoly(const ImVec2* points, const int num_points);
147 |
148 | // Sliding bar for splits. label: used to calculate the ID. window:
149 | // window containing the bar. pos: position of the top left of the bar on
150 | // input and output. size: size of the bar. minx and maxx: minimum and maximum
151 | // positions in direction direction (1=x, 2=y).
152 | void SlidingBar(const char* label, ImGuiWindow* window, ImVec2 *pos, ImVec2 size,
153 | float minx, float maxx, int direction);
154 |
155 | // Button with a clickable "X" at the end. label: label for the
156 | // button (and generates the ID of the main button). size: size of
157 | // the button. activetab: whether the button uses the "active" or
158 | // "inactive" color. scrollbarcol: if true, use scroll bar grab
159 | // colors (otherwise, use framebg colors). p_open whether the "x" is
160 | // shown and close status. dragged: on output, true if the button is
161 | // being dragged. dclicked: on output, true if the button was double
162 | // clicked. closeclicked: on output, true if the X has been clicked.
163 | // alphamul: alpha multiplier for all colors. Returns true if the
164 | // main part of the button (not the x) has been clicked.
165 | bool ButtonWithX(const char* label, const ImVec2& size, bool activetab,
166 | bool *p_open, bool *dragged, bool *dclicked, float alpha = 1.f);
167 |
168 | // A resize grip drawn on window that controls the size of cwindow.
169 | // On output, dclicked is true if double-click (auto-resize)
170 | // happened.
171 | void ResizeGripOther(const char *label, ImGuiWindow* window, ImGuiWindow* cwindow, bool *dclicked=nullptr);
172 |
173 | // Lift grip. A grip the with button colors drawn on the bottom left
174 | // corner of the window. True if the grip is clicked.
175 | bool LiftGrip(const char *label, ImGuiWindow* window);
176 |
177 | // xxxx //
178 | bool ImageInteractive(ImTextureID texture, float a, bool *hover, ImRect *vrect);
179 |
180 | // xxxx //
181 | bool InvisibleButtonEx(const char* str_id, const ImVec2& size_arg, bool* hovered, bool *held);
182 |
183 | // xxxx //
184 | void AttachTooltip(const char* desc, float delay, float maxwidth, ImFont* font);
185 |
186 | } // namespace ImGui
187 |
188 | #endif
189 |
190 |
--------------------------------------------------------------------------------