Seperated single header out into multiple files

Nuklear now comes in two flavours. For ones there is the single-header
version for distribution and multiple files inside the /src folder for
development and better readability. Since I don't want to manually
update each version if the other changes the /src directory includes a
python script developed by Apoorva Joshi to pack all files inside the
directory into a single header file.
master
vurtun 2018-04-02 18:03:03 +02:00
parent 9a8899fb29
commit f5aa92c5ca
49 changed files with 31460 additions and 6342 deletions

12488
nuklear.h

File diff suppressed because it is too large Load Diff

278
src/CHANGELOG Normal file
View File

@ -0,0 +1,278 @@
/// ## Changelog
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
/// [date][x.yy.zz]-[description]
/// -[date]: date on which the change has been pushed
/// -[x.yy.zz]: Numerical version string representation. Each version number on the right
/// resets back to zero if version on the left is incremented.
/// - [x]: Major version with API and library breaking changes
/// - [yy]: Minor version with non-breaking API and library changes
/// - [zz]: Bug fix version with no direct changes to API
///
/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame
/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to
/// clear provided buffers. So make sure to either free
/// or clear each passed buffer after calling nk_convert.
/// - 2018/02/23 (3.00.6) - Fixed slider dragging behavior
/// - 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process
/// - 2018/01/31 (3.00.4) - Removed name collision with stb_truetype
/// - 2018/01/28 (3.00.3) - Fixed panel window border drawing bug
/// - 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separed group identifier and title
/// - 2018/01/07 (3.00.1) - Started to change documentation style
/// - 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken
/// because of conversions between float and byte color representation.
/// Color pickers now use floating point values to represent
/// HSV values. To get back the old behavior I added some additional
/// color conversion functions to cast between nk_color and
/// nk_colorf.
/// - 2017/12/23 (2.00.7) - Fixed small warning
/// - 2017/12/23 (2.00.7) - Fixed nk_edit_buffer behavior if activated to allow input
/// - 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior
/// - 2017/12/04 (2.00.6) - Added formated string tooltip widget
/// - 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag NK_WINDOW_NO_INPUT
/// - 2017/11/15 (2.00.4) - Fixed font merging
/// - 2017/11/07 (2.00.3) - Fixed window size and position modifier functions
/// - 2017/09/14 (2.00.2) - Fixed nk_edit_buffer and nk_edit_focus behavior
/// - 2017/09/14 (2.00.1) - Fixed window closing behavior
/// - 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifing window position and size funtions now
/// require the name of the window and must happen outside the window
/// building process (between function call nk_begin and nk_end).
/// - 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last
/// - 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows
/// - 2017/08/27 (1.40.7) - Fixed window background flag
/// - 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked
/// query for widgets
/// - 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked
/// and filled rectangles
/// - 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in
/// process of being destroyed.
/// - 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in
/// window instead of directly in table.
/// - 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro
/// - 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero
/// - 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only
/// comes in effect if you pass in zero was row height argument
/// - 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change
/// how layouting works. From now there will be an internal minimum
/// row height derived from font height. If you need a row smaller than
/// that you can directly set it by `nk_layout_set_min_row_height` and
/// reset the value back by calling `nk_layout_reset_min_row_height.
/// - 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix
/// - 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a nk_layout_xxx function
/// - 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer
/// - 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped
/// - 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundries
/// - 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space
/// - 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size
/// - 2017/05/06 (1.38.0) - Added platform double-click support
/// - 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends
/// - 2017/04/20 (1.37.0) - Extended properties with selection and clipbard support
/// - 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing
/// - 2017/04/09 (1.36.1) - Fixed #403 with another widget float error
/// - 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags
/// - 2017/04/09 (1.35.3) - Fixed buffer heap corruption
/// - 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows
/// - 2017/03/25 (1.35.1) - Fixed windows closing behavior
/// - 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377
/// - 2017/03/18 (1.34.3) - Fixed long window header titles
/// - 2017/03/04 (1.34.2) - Fixed text edit filtering
/// - 2017/03/04 (1.34.1) - Fixed group closable flag
/// - 2017/02/25 (1.34.0) - Added custom draw command for better language binding support
/// - 2017/01/24 (1.33.0) - Added programatic way of remove edit focus
/// - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows
/// - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows
/// - 2017/01/21 (1.32.1) - Fixed slider behavior and drawing
/// - 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner
/// - 2017/01/13 (1.31.0) - Added additional row layouting method to combine both
/// dynamic and static widgets.
/// - 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit
/// - 2016/12/31 (1.29.2)- Fixed closing window bug of minimized windows
/// - 2016/12/03 (1.29.1)- Fixed wrapped text with no seperator and C89 error
/// - 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters
/// - 2016/11/22 (1.28.6)- Fixed window minimized closing bug
/// - 2016/11/19 (1.28.5)- Fixed abstract combo box closing behavior
/// - 2016/11/19 (1.28.4)- Fixed tooltip flickering
/// - 2016/11/19 (1.28.3)- Fixed memory leak caused by popup repeated closing
/// - 2016/11/18 (1.28.2)- Fixed memory leak caused by popup panel allocation
/// - 2016/11/10 (1.28.1)- Fixed some warnings and C++ error
/// - 2016/11/10 (1.28.0)- Added additional `nk_button` versions which allows to directly
/// pass in a style struct to change buttons visual.
/// - 2016/11/10 (1.27.0)- Added additional 'nk_tree' versions to support external state
/// storage. Just like last the `nk_group` commit the main
/// advantage is that you optionally can minimize nuklears runtime
/// memory consumption or handle hash collisions.
/// - 2016/11/09 (1.26.0)- Added additional `nk_group` version to support external scrollbar
/// offset storage. Main advantage is that you can externalize
/// the memory management for the offset. It could also be helpful
/// if you have a hash collision in `nk_group_begin` but really
/// want the name. In addition I added `nk_list_view` which allows
/// to draw big lists inside a group without actually having to
/// commit the whole list to nuklear (issue #269).
/// - 2016/10/30 (1.25.1)- Fixed clipping rectangle bug inside `nk_draw_list`
/// - 2016/10/29 (1.25.0)- Pulled `nk_panel` memory management into nuklear and out of
/// the hands of the user. From now on users don't have to care
/// about panels unless they care about some information. If you
/// still need the panel just call `nk_window_get_panel`.
/// - 2016/10/21 (1.24.0)- Changed widget border drawing to stroked rectangle from filled
/// rectangle for less overdraw and widget background transparency.
/// - 2016/10/18 (1.23.0)- Added `nk_edit_focus` for manually edit widget focus control
/// - 2016/09/29 (1.22.7)- Fixed deduction of basic type in non `<stdint.h>` compilation
/// - 2016/09/29 (1.22.6)- Fixed edit widget UTF-8 text cursor drawing bug
/// - 2016/09/28 (1.22.5)- Fixed edit widget UTF-8 text appending/inserting/removing
/// - 2016/09/28 (1.22.4)- Fixed drawing bug inside edit widgets which offset all text
/// text in every edit widget if one of them is scrolled.
/// - 2016/09/28 (1.22.3)- Fixed small bug in edit widgets if not active. The wrong
/// text length is passed. It should have been in bytes but
/// was passed as glyphes.
/// - 2016/09/20 (1.22.2)- Fixed color button size calculation
/// - 2016/09/20 (1.22.1)- Fixed some `nk_vsnprintf` behavior bugs and removed
/// `<stdio.h>` again from `NK_INCLUDE_STANDARD_VARARGS`.
/// - 2016/09/18 (1.22.0)- C89 does not support vsnprintf only C99 and newer as well
/// as C++11 and newer. In addition to use vsnprintf you have
/// to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`
/// is not enough. That behavior is now fixed. By default if
/// both varargs as well as stdio is selected I try to use
/// vsnprintf if not possible I will revert to vsprintf. If
/// varargs but not stdio was defined I will use my own function.
/// - 2016/09/15 (1.21.2)- Fixed panel `close` behavior for deeper panel levels
/// - 2016/09/15 (1.21.1)- Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`
/// - 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,
/// and contextual which prevented closing in y-direction if
/// popup did not reach max height.
/// In addition the height parameter was changed into vec2
/// for width and height to have more control over the popup size.
/// - 2016/09/13 (1.20.3) - Cleaned up and extended type selection
/// - 2016/09/13 (1.20.2)- Fixed slider behavior hopefully for the last time. This time
/// all calculation are correct so no more hackery.
/// - 2016/09/13 (1.20.1)- Internal change to divide window/panel flags into panel flags and types.
/// Suprisinly spend years in C and still happened to confuse types
/// with flags. Probably something to take note.
/// - 2016/09/08 (1.20.0)- Added additional helper function to make it easier to just
/// take the produced buffers from `nk_convert` and unplug the
/// iteration process from `nk_context`. So now you can
/// just use the vertex,element and command buffer + two pointer
/// inside the command buffer retrieved by calls `nk__draw_begin`
/// and `nk__draw_end` and macro `nk_draw_foreach_bounded`.
/// - 2016/09/08 (1.19.0)- Added additional asserts to make sure every `nk_xxx_begin` call
/// for windows, popups, combobox, menu and contextual is guarded by
/// `if` condition and does not produce false drawing output.
/// - 2016/09/08 (1.18.0)- Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`
/// to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and
/// `NK_SYMBOL_RECT_OUTLINE`.
/// - 2016/09/08 (1.17.0)- Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`
/// to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and
/// `NK_SYMBOL_CIRCLE_OUTLINE`.
/// - 2016/09/08 (1.16.0)- Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`
/// is not defined by supporting the biggest compiler GCC, clang and MSVC.
/// - 2016/09/07 (1.15.3)- Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error
/// - 2016/09/04 (1.15.2)- Fixed wrong combobox height calculation
/// - 2016/09/03 (1.15.1)- Fixed gaps inside combo boxes in OpenGL
/// - 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and
/// instead made it user provided. The range of types to convert
/// to is quite limited at the moment, but I would be more than
/// happy to accept PRs to add additional.
/// - 2016/08/30 (1.14.2) - Removed unused variables
/// - 2016/08/30 (1.14.1) - Fixed C++ build errors
/// - 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly
/// - 2016/08/30 (1.13.4) - Tweaked some default styling variables
/// - 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would
/// refrain from using slider with a big number of steps.
/// - 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the
/// window was in Read Only Mode.
/// - 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just
/// a hack for combo box and menu.
/// - 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since
/// it is bugged and causes issues in window selection.
/// - 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now
/// determined by the scrollbar size
/// - 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11
/// - 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection
/// - 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code
/// handling panel padding and panel border.
/// - 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx`
/// - 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups
/// - 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes
/// - 2016/08/26 (1.10.0) - Added window name string prepresentation to account for
/// hash collisions. Currently limited to NK_WINDOW_MAX_NAME
/// which in term can be redefined if not big enough.
/// - 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code
/// - 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'
/// to account for key press and release happening in one frame.
/// - 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate
/// - 2016/08/17 (1.09.6)- Removed invalid check for value zero in nk_propertyx
/// - 2016/08/16 (1.09.5)- Fixed ROM mode for deeper levels of popup windows parents.
/// - 2016/08/15 (1.09.4)- Editbox are now still active if enter was pressed with flag
/// `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep
/// typing after commiting.
/// - 2016/08/15 (1.09.4)- Removed redundant code
/// - 2016/08/15 (1.09.4)- Fixed negative numbers in `nk_strtoi` and remove unused variable
/// - 2016/08/15 (1.09.3)- Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background
/// window only as selected by hovering and not by clicking.
/// - 2016/08/14 (1.09.2)- Fixed a bug in font atlas which caused wrong loading
/// of glyphes for font with multiple ranges.
/// - 2016/08/12 (1.09.1)- Added additional function to check if window is currently
/// hidden and therefore not visible.
/// - 2016/08/12 (1.09.1)- nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`
/// instead of the old flag `NK_WINDOW_HIDDEN`
/// - 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed
/// the underlying implementation to not cast to float and instead
/// work directly on the given values.
/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal
/// floating pointer number to string conversion for additional
/// precision.
/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal
/// string to floating point number conversion for additional
/// precision.
/// - 2016/08/08 (1.07.2)- Fixed compiling error without define NK_INCLUDE_FIXED_TYPE
/// - 2016/08/08 (1.07.1)- Fixed possible floating point error inside `nk_widget` leading
/// to wrong wiget width calculation which results in widgets falsly
/// becomming tagged as not inside window and cannot be accessed.
/// - 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and
/// closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown
/// by using `nk_window_show` and closed by either clicking the close
/// icon in a window or by calling `nk_window_close`. Only closed
/// windows get removed at the end of the frame while hidden windows
/// remain.
/// - 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to
/// `nk_edit_string` which takes, edits and outputs a '\0' terminated string.
/// - 2016/08/08 (1.05.4)- Fixed scrollbar auto hiding behavior
/// - 2016/08/08 (1.05.3)- Fixed wrong panel padding selection in `nk_layout_widget_space`
/// - 2016/08/07 (1.05.2)- Fixed old bug in dynamic immediate mode layout API, calculating
/// wrong item spacing and panel width.
///- 2016/08/07 (1.05.1)- Hopefully finally fixed combobox popup drawing bug
///- 2016/08/07 (1.05.0) - Split varargs away from NK_INCLUDE_STANDARD_IO into own
/// define NK_INCLUDE_STANDARD_VARARGS to allow more fine
/// grained controlled over library includes.
/// - 2016/08/06 (1.04.5)- Changed memset calls to NK_MEMSET
/// - 2016/08/04 (1.04.4)- Fixed fast window scaling behavior
/// - 2016/08/04 (1.04.3)- Fixed window scaling, movement bug which appears if you
/// move/scale a window and another window is behind it.
/// If you are fast enough then the window behind gets activated
/// and the operation is blocked. I now require activating
/// by hovering only if mouse is not pressed.
/// - 2016/08/04 (1.04.2)- Fixed changing fonts
/// - 2016/08/03 (1.04.1)- Fixed `NK_WINDOW_BACKGROUND` behavior
/// - 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image`
/// - 2016/08/03 (1.04.0) - Added additional window padding style attributes for
/// sub windows (combo, menu, ...)
/// - 2016/08/03 (1.04.0) - Added functions to show/hide software cursor
/// - 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window
/// to be always in the background of the screen
/// - 2016/08/03 (1.03.2)- Removed invalid assert macro for NK_RGB color picker
/// - 2016/08/01 (1.03.1)- Added helper macros into header include guard
/// - 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to
/// simplify memory management by removing the need to
/// allocate the pool.
/// - 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled
/// will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT
/// seconds without window interaction. To make it work
/// you have to also set a delta time inside the `nk_context`.
/// - 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs
/// - 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context`
/// - 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument
/// - 2016/07/15 (1.01.0) - Removed internal font baking API and simplified
/// font atlas memory management by converting pointer
/// arrays for fonts and font configurations to lists.
/// - 2016/07/15 (1.00.0) - Changed button API to use context dependend button
/// behavior instead of passing it for every function call.
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

24
src/CREDITS Normal file
View File

@ -0,0 +1,24 @@
/// ## Gallery
/// ![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)
/// ![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)
/// ![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png)
/// ![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png)
/// ![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png)
/// ![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png)
/// ![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)
/// ![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)
/// ![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)
///
/// ## Credits
/// Developed by Micha Mettke and every direct or indirect github contributor. <br /><br />
///
/// Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain) <br />
/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation <br /><br />
/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). <br />
///
/// Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and
/// giving me the inspiration for this library, Casey Muratori for handmade hero
/// and his original immediate mode graphical user interface idea and Sean
/// Barret for his amazing single header libraries which restored my faith
/// in libraries and brought me to create some of my own. Finally Apoorva Joshi
/// for his single header file packer.

210
src/HEADER Normal file
View File

@ -0,0 +1,210 @@
/// # Nuklear
/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
///
/// ## Contents
/// 1. About section
/// 2. Highlights section
/// 3. Features section
/// 4. Usage section
/// 1. Flags section
/// 2. Constants section
/// 3. Dependencies section
/// 5. Example section
/// 6. API section
/// 1. Context section
/// 2. Input section
/// 3. Drawing section
/// 4. Window section
/// 5. Layouting section
/// 6. Groups section
/// 7. Tree section
/// 8. Properties section
/// 7. License section
/// 8. Changelog section
/// 9. Gallery section
/// 10. Credits section
///
/// ## About
/// This is a minimal state immediate mode graphical user interface toolkit
/// written in ANSI C and licensed under public domain. It was designed as a simple
/// embeddable user interface for application and does not have any dependencies,
/// a default renderbackend or OS window and input handling but instead provides a very modular
/// library approach by using simple input state for input and draw
/// commands describing primitive shapes as output. So instead of providing a
/// layered library that tries to abstract over a number of platform and
/// render backends it only focuses on the actual UI.
///
/// ## Highlights
/// - Graphical user interface toolkit
/// - Single header library
/// - Written in C89 (a.k.a. ANSI C or ISO C90)
/// - Small codebase (~18kLOC)
/// - Focus on portability, efficiency and simplicity
/// - No dependencies (not even the standard library if not wanted)
/// - Fully skinnable and customizable
/// - Low memory footprint with total memory control if needed or wanted
/// - UTF-8 support
/// - No global or hidden state
/// - Customizable library modules (you can compile and use only what you need)
/// - Optional font baker and vertex buffer output
///
/// ## Features
/// - Absolutely no platform dependent code
/// - Memory management control ranging from/to
/// - Ease of use by allocating everything from standard library
/// - Control every byte of memory inside the library
/// - Font handling control ranging from/to
/// - Use your own font implementation for everything
/// - Use this libraries internal font baking and handling API
/// - Drawing output control ranging from/to
/// - Simple shapes for more high level APIs which already have drawing capabilities
/// - Hardware accessible anti-aliased vertex buffer output
/// - Customizable colors and properties ranging from/to
/// - Simple changes to color by filling a simple color table
/// - Complete control with ability to use skinning to decorate widgets
/// - Bendable UI library with widget ranging from/to
/// - Basic widgets like buttons, checkboxes, slider, ...
/// - Advanced widget like abstract comboboxes, contextual menus,...
/// - Compile time configuration to only compile what you need
/// - Subset which can be used if you do not want to link or use the standard library
/// - Can be easily modified to only update on user input instead of frame updates
///
/// ## Usage
/// This library is self contained in one single header file and can be used either
/// in header only mode or in implementation mode. The header only mode is used
/// by default when included and allows including this header in other headers
/// and does not contain the actual implementation. <br /><br />
///
/// The implementation mode requires to define the preprocessor macro
/// NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.:
///
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C
/// #define NK_IMPLEMENTATION
/// #include "nuklear.h"
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///
/// Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
/// below in header and implementation mode if you want to use additional functionality
/// or need more control over the library.
///
/// !!! WARNING
/// Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.
///
/// ### Flags
/// Flag | Description
/// --------------------------------|------------------------------------------
/// NK_PRIVATE | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation
/// NK_INCLUDE_FIXED_TYPES | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
/// NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
/// NK_INCLUDE_STANDARD_IO | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
/// NK_INCLUDE_STANDARD_VARARGS | If defined it will include header <stdio.h> and provide additional functions depending on file loading.
/// NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
/// NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
/// NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
/// NK_INCLUDE_COMMAND_USERDATA | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.
/// NK_BUTTON_TRIGGER_ON_RELEASE | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.
/// NK_ZERO_COMMAND_MEMORY | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.
///
/// !!! WARNING
/// The following flags will pull in the standard C library:
/// - NK_INCLUDE_DEFAULT_ALLOCATOR
/// - NK_INCLUDE_STANDARD_IO
/// - NK_INCLUDE_STANDARD_VARARGS
///
/// !!! WARNING
/// The following flags if defined need to be defined for both header and implementation:
/// - NK_INCLUDE_FIXED_TYPES
/// - NK_INCLUDE_DEFAULT_ALLOCATOR
/// - NK_INCLUDE_STANDARD_VARARGS
/// - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
/// - NK_INCLUDE_FONT_BAKING
/// - NK_INCLUDE_DEFAULT_FONT
/// - NK_INCLUDE_STANDARD_VARARGS
/// - NK_INCLUDE_COMMAND_USERDATA
///
/// ### Constants
/// Define | Description
/// --------------------------------|---------------------------------------
/// NK_BUFFER_DEFAULT_INITIAL_SIZE | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.
/// NK_MAX_NUMBER_BUFFER | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.
/// NK_INPUT_MAX | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.
///
/// !!! WARNING
/// The following constants if defined need to be defined for both header and implementation:
/// - NK_MAX_NUMBER_BUFFER
/// - NK_BUFFER_DEFAULT_INITIAL_SIZE
/// - NK_INPUT_MAX
///
/// ### Dependencies
/// Function | Description
/// ------------|---------------------------------------------------------------
/// NK_ASSERT | If you don't define this, nuklear will use <assert.h> with assert().
/// NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
/// NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
/// NK_SQRT | You can define this to 'sqrt' or your own sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
/// NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
/// NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
/// NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
/// NK_DTOA | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
/// NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
///
/// !!! WARNING
/// The following dependencies will pull in the standard C library if not redefined:
/// - NK_ASSERT
///
/// !!! WARNING
/// The following dependencies if defined need to be defined for both header and implementation:
/// - NK_ASSERT
///
/// !!! WARNING
/// The following dependencies if defined need to be defined only for the implementation part:
/// - NK_MEMSET
/// - NK_MEMCPY
/// - NK_SQRT
/// - NK_SIN
/// - NK_COS
/// - NK_STRTOD
/// - NK_DTOA
/// - NK_VSNPRINTF
///
/// ## Example
///
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
/// // init gui state
/// enum {EASY, HARD};
/// static int op = EASY;
/// static float value = 0.6f;
/// static int i = 20;
/// struct nk_context ctx;
///
/// nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
/// if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
/// NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
/// // fixed widget pixel width
/// nk_layout_row_static(&ctx, 30, 80, 1);
/// if (nk_button_label(&ctx, "button")) {
/// // event handling
/// }
///
/// // fixed widget window ratio width
/// nk_layout_row_dynamic(&ctx, 30, 2);
/// if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
/// if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
///
/// // custom widget pixel width
/// nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
/// {
/// nk_layout_row_push(&ctx, 50);
/// nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
/// nk_layout_row_push(&ctx, 110);
/// nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
/// }
/// nk_layout_row_end(&ctx);
/// }
/// nk_end(&ctx);
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///
/// ![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
///
/// ## API
///

43
src/LICENSE Normal file
View File

@ -0,0 +1,43 @@
/// ## License
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
/// ------------------------------------------------------------------------------
/// This software is available under 2 licenses -- choose whichever you prefer.
/// ------------------------------------------------------------------------------
/// ALTERNATIVE A - MIT License
/// Copyright (c) 2016-2018 Micha Mettke
/// Permission is hereby granted, free of charge, to any person obtaining a copy of
/// this software and associated documentation files (the "Software"), to deal in
/// the Software without restriction, including without limitation the rights to
/// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
/// of the Software, and to permit persons to whom the Software is furnished to do
/// so, subject to the following conditions:
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
/// ------------------------------------------------------------------------------
/// ALTERNATIVE B - Public Domain (www.unlicense.org)
/// This is free and unencumbered software released into the public domain.
/// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
/// software, either in source code form or as a compiled binary, for any purpose,
/// commercial or non-commercial, and by any means.
/// In jurisdictions that recognize copyright laws, the author or authors of this
/// software dedicate any and all copyright interest in the software to the public
/// domain. We make this dedication for the benefit of the public at large and to
/// the detriment of our heirs and successors. We intend this dedication to be an
/// overt act of relinquishment in perpetuity of all present and future rights to
/// this software under copyright law.
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
/// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/// ------------------------------------------------------------------------------
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

146
src/build.py Normal file
View File

@ -0,0 +1,146 @@
import fnmatch
import os.path
import sys
def print_help():
print(
"""usage: python single_header_packer.py --macro <macro> [--intro <files>] --pub <files> --priv <files> [--outro <files>]
where <files> can be a comma-separated list of files. e.g. --priv *.c,inc/*.h
The resulting code is packed as follows:
/*
[intro file contents]
*/
#ifndef <macro>_SINGLE_HEADER
#define <macro>_SINGLE_HEADER
[public header file contents]
#endif /* <macro>_SINGLE_HEADER */
#ifdef <macro>_IMPLEMENTATION
[private header and source file contents]
#endif /* <macro>_IMPLEMENTATION */
/*
[outro file contents]
*/""")
def parse_files(arg):
files = []
paths = arg.split(",")
for path in paths:
if "*" in path:
# Wildcard
d = os.path.dirname(path)
if d == "": d = "."
if d == " ": continue
if not os.path.exists(d):
print(d + " does not exist.")
exit()
wildcard = os.path.basename(path)
unsorted = []
for file in os.listdir(d):
if fnmatch.fnmatch(file, wildcard):
unsorted.append(os.path.join(d, file))
unsorted.sort()
files.extend(unsorted)
else:
# Regular file
if not os.path.exists(path):
print(path + " does not exist.")
exit()
elif os.path.isdir(path):
print(path + " is a directory. Expected a file name.")
exit()
else:
files.append(path)
return files;
def omit_includes(str, files):
for file in files:
fname = os.path.basename(file)
if ".h" in file:
str = str.replace("#include \"" + fname + "\"", "");
str = str.replace("#include <" + fname + ">", "");
return str
# Main start
# ==========
if len(sys.argv) < 2:
print_help()
exit()
intro_files = []
pub_files = []
priv_files = []
outro_files = []
cur_arg = 1
macro = ""
# Parse args
# ----------
while cur_arg < len(sys.argv):
if sys.argv[cur_arg] == "--help":
print_help()
exit()
elif sys.argv[cur_arg] == "--macro":
cur_arg += 1
macro = sys.argv[cur_arg]
elif sys.argv[cur_arg] == "--intro":
cur_arg += 1
intro_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--pub":
cur_arg += 1
pub_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--priv":
cur_arg += 1
priv_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--outro":
cur_arg += 1
outro_files = parse_files(sys.argv[cur_arg])
else:
print("Unknown argument " + sys.argv[cur_arg])
cur_arg += 1
if macro == "":
print("Option --macro <macro> is mandatory")
exit()
# Print concatenated output
# -------------------------
print("/*")
for f in intro_files:
sys.stdout.write(open(f, 'r').read())
print("*/")
# print(os.linesep + "#ifndef " + macro + "_SINGLE_HEADER");
# print("#define " + macro + "_SINGLE_HEADER");
print("#ifndef NK_SINGLE_FILE");
print(" #define NK_SINGLE_FILE");
print("#endif");
print("");
for f in pub_files:
sys.stdout.write(open(f, 'r').read())
# print("#endif /* " + macro + "_SINGLE_HEADER */");
print(os.linesep + "#ifdef " + macro + "_IMPLEMENTATION");
print("");
for f in priv_files:
print(omit_includes(open(f, 'r').read(),
pub_files + priv_files))
print("#endif /* " + macro + "_IMPLEMENTATION */");
print(os.linesep + "/*")
for f in outro_files:
sys.stdout.write(open(f, 'r').read())
print("*/" + os.linesep)

5366
src/nuklear.h Normal file

File diff suppressed because it is too large Load Diff

277
src/nuklear_buffer.c Normal file
View File

@ -0,0 +1,277 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* BUFFER
*
* ===============================================================*/
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_LIB void*
nk_malloc(nk_handle unused, void *old,nk_size size)
{
NK_UNUSED(unused);
NK_UNUSED(old);
return malloc(size);
}
NK_LIB void
nk_mfree(nk_handle unused, void *ptr)
{
NK_UNUSED(unused);
free(ptr);
}
NK_API void
nk_buffer_init_default(struct nk_buffer *buffer)
{
struct nk_allocator alloc;
alloc.userdata.ptr = 0;
alloc.alloc = nk_malloc;
alloc.free = nk_mfree;
nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);
}
#endif
NK_API void
nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,
nk_size initial_size)
{
NK_ASSERT(b);
NK_ASSERT(a);
NK_ASSERT(initial_size);
if (!b || !a || !initial_size) return;
nk_zero(b, sizeof(*b));
b->type = NK_BUFFER_DYNAMIC;
b->memory.ptr = a->alloc(a->userdata,0, initial_size);
b->memory.size = initial_size;
b->size = initial_size;
b->grow_factor = 2.0f;
b->pool = *a;
}
NK_API void
nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)
{
NK_ASSERT(b);
NK_ASSERT(m);
NK_ASSERT(size);
if (!b || !m || !size) return;
nk_zero(b, sizeof(*b));
b->type = NK_BUFFER_FIXED;
b->memory.ptr = m;
b->memory.size = size;
b->size = size;
}
NK_LIB void*
nk_buffer_align(void *unaligned,
nk_size align, nk_size *alignment,
enum nk_buffer_allocation_type type)
{
void *memory = 0;
switch (type) {
default:
case NK_BUFFER_MAX:
case NK_BUFFER_FRONT:
if (align) {
memory = NK_ALIGN_PTR(unaligned, align);
*alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
} else {
memory = unaligned;
*alignment = 0;
}
break;
case NK_BUFFER_BACK:
if (align) {
memory = NK_ALIGN_PTR_BACK(unaligned, align);
*alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);
} else {
memory = unaligned;
*alignment = 0;
}
break;
}
return memory;
}
NK_LIB void*
nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
{
void *temp;
nk_size buffer_size;
NK_ASSERT(b);
NK_ASSERT(size);
if (!b || !size || !b->pool.alloc || !b->pool.free)
return 0;
buffer_size = b->memory.size;
temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
NK_ASSERT(temp);
if (!temp) return 0;
*size = capacity;
if (temp != b->memory.ptr) {
NK_MEMCPY(temp, b->memory.ptr, buffer_size);
b->pool.free(b->pool.userdata, b->memory.ptr);
}
if (b->size == buffer_size) {
/* no back buffer so just set correct size */
b->size = capacity;
return temp;
} else {
/* copy back buffer to the end of the new buffer */
void *dst, *src;
nk_size back_size;
back_size = buffer_size - b->size;
dst = nk_ptr_add(void, temp, capacity - back_size);
src = nk_ptr_add(void, temp, b->size);
NK_MEMCPY(dst, src, back_size);
b->size = capacity - back_size;
}
return temp;
}
NK_LIB void*
nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,
nk_size size, nk_size align)
{
int full;
nk_size alignment;
void *unaligned;
void *memory;
NK_ASSERT(b);
NK_ASSERT(size);
if (!b || !size) return 0;
b->needed += size;
/* calculate total size with needed alignment + size */
if (type == NK_BUFFER_FRONT)
unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
memory = nk_buffer_align(unaligned, align, &alignment, type);
/* check if buffer has enough memory*/
if (type == NK_BUFFER_FRONT)
full = ((b->allocated + size + alignment) > b->size);
else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);
if (full) {
nk_size capacity;
if (b->type != NK_BUFFER_DYNAMIC)
return 0;
NK_ASSERT(b->pool.alloc && b->pool.free);
if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)
return 0;
/* buffer is full so allocate bigger buffer if dynamic */
capacity = (nk_size)((float)b->memory.size * b->grow_factor);
capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));
b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);
if (!b->memory.ptr) return 0;
/* align newly allocated pointer */
if (type == NK_BUFFER_FRONT)
unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
memory = nk_buffer_align(unaligned, align, &alignment, type);
}
if (type == NK_BUFFER_FRONT)
b->allocated += size + alignment;
else b->size -= (size + alignment);
b->needed += alignment;
b->calls++;
return memory;
}
NK_API void
nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,
const void *memory, nk_size size, nk_size align)
{
void *mem = nk_buffer_alloc(b, type, size, align);
if (!mem) return;
NK_MEMCPY(mem, memory, size);
}
NK_API void
nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
{
NK_ASSERT(buffer);
if (!buffer) return;
buffer->marker[type].active = nk_true;
if (type == NK_BUFFER_BACK)
buffer->marker[type].offset = buffer->size;
else buffer->marker[type].offset = buffer->allocated;
}
NK_API void
nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
{
NK_ASSERT(buffer);
if (!buffer) return;
if (type == NK_BUFFER_BACK) {
/* reset back buffer either back to marker or empty */
buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);
if (buffer->marker[type].active)
buffer->size = buffer->marker[type].offset;
else buffer->size = buffer->memory.size;
buffer->marker[type].active = nk_false;
} else {
/* reset front buffer either back to back marker or empty */
buffer->needed -= (buffer->allocated - buffer->marker[type].offset);
if (buffer->marker[type].active)
buffer->allocated = buffer->marker[type].offset;
else buffer->allocated = 0;
buffer->marker[type].active = nk_false;
}
}
NK_API void
nk_buffer_clear(struct nk_buffer *b)
{
NK_ASSERT(b);
if (!b) return;
b->allocated = 0;
b->size = b->memory.size;
b->calls = 0;
b->needed = 0;
}
NK_API void
nk_buffer_free(struct nk_buffer *b)
{
NK_ASSERT(b);
if (!b || !b->memory.ptr) return;
if (b->type == NK_BUFFER_FIXED) return;
if (!b->pool.free) return;
NK_ASSERT(b->pool.free);
b->pool.free(b->pool.userdata, b->memory.ptr);
}
NK_API void
nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b)
{
NK_ASSERT(b);
NK_ASSERT(s);
if (!s || !b) return;
s->allocated = b->allocated;
s->size = b->memory.size;
s->needed = b->needed;
s->memory = b->memory.ptr;
s->calls = b->calls;
}
NK_API void*
nk_buffer_memory(struct nk_buffer *buffer)
{
NK_ASSERT(buffer);
if (!buffer) return 0;
return buffer->memory.ptr;
}
NK_API const void*
nk_buffer_memory_const(const struct nk_buffer *buffer)
{
NK_ASSERT(buffer);
if (!buffer) return 0;
return buffer->memory.ptr;
}
NK_API nk_size
nk_buffer_total(struct nk_buffer *buffer)
{
NK_ASSERT(buffer);
if (!buffer) return 0;
return buffer->memory.size;
}

666
src/nuklear_button.c Normal file
View File

@ -0,0 +1,666 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* BUTTON
*
* ===============================================================*/
NK_LIB void
nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,
struct nk_rect content, struct nk_color background, struct nk_color foreground,
float border_width, const struct nk_user_font *font)
{
switch (type) {
case NK_SYMBOL_X:
case NK_SYMBOL_UNDERSCORE:
case NK_SYMBOL_PLUS:
case NK_SYMBOL_MINUS: {
/* single character text symbol */
const char *X = (type == NK_SYMBOL_X) ? "x":
(type == NK_SYMBOL_UNDERSCORE) ? "_":
(type == NK_SYMBOL_PLUS) ? "+": "-";
struct nk_text text;
text.padding = nk_vec2(0,0);
text.background = background;
text.text = foreground;
nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);
} break;
case NK_SYMBOL_CIRCLE_SOLID:
case NK_SYMBOL_CIRCLE_OUTLINE:
case NK_SYMBOL_RECT_SOLID:
case NK_SYMBOL_RECT_OUTLINE: {
/* simple empty/filled shapes */
if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {
nk_fill_rect(out, content, 0, foreground);
if (type == NK_SYMBOL_RECT_OUTLINE)
nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);
} else {
nk_fill_circle(out, content, foreground);
if (type == NK_SYMBOL_CIRCLE_OUTLINE)
nk_fill_circle(out, nk_shrink_rect(content, 1), background);
}
} break;
case NK_SYMBOL_TRIANGLE_UP:
case NK_SYMBOL_TRIANGLE_DOWN:
case NK_SYMBOL_TRIANGLE_LEFT:
case NK_SYMBOL_TRIANGLE_RIGHT: {
enum nk_heading heading;
struct nk_vec2 points[3];
heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :
(type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:
(type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;
nk_triangle_from_direction(points, content, 0, 0, heading);
nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,
points[2].x, points[2].y, foreground);
} break;
default:
case NK_SYMBOL_NONE:
case NK_SYMBOL_MAX: break;
}
}
NK_LIB int
nk_button_behavior(nk_flags *state, struct nk_rect r,
const struct nk_input *i, enum nk_button_behavior behavior)
{
int ret = 0;
nk_widget_state_reset(state);
if (!i) return 0;
if (nk_input_is_mouse_hovering_rect(i, r)) {
*state = NK_WIDGET_STATE_HOVERED;
if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))
*state = NK_WIDGET_STATE_ACTIVE;
if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) {
ret = (behavior != NK_BUTTON_DEFAULT) ?
nk_input_is_mouse_down(i, NK_BUTTON_LEFT):
#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
nk_input_is_mouse_released(i, NK_BUTTON_LEFT);
#else
nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);
#endif
}
}
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(i, r))
*state |= NK_WIDGET_STATE_LEFT;
return ret;
}
NK_LIB const struct nk_style_item*
nk_draw_button(struct nk_command_buffer *out,
const struct nk_rect *bounds, nk_flags state,
const struct nk_style_button *style)
{
const struct nk_style_item *background;
if (state & NK_WIDGET_STATE_HOVER)
background = &style->hover;
else if (state & NK_WIDGET_STATE_ACTIVED)
background = &style->active;
else background = &style->normal;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
} else {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
}
return background;
}
NK_LIB int
nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,
const struct nk_style_button *style, const struct nk_input *in,
enum nk_button_behavior behavior, struct nk_rect *content)
{
struct nk_rect bounds;
NK_ASSERT(style);
NK_ASSERT(state);
NK_ASSERT(out);
if (!out || !style)
return nk_false;
/* calculate button content space */
content->x = r.x + style->padding.x + style->border + style->rounding;
content->y = r.y + style->padding.y + style->border + style->rounding;
content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2);
content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2);
/* execute button behavior */
bounds.x = r.x - style->touch_padding.x;
bounds.y = r.y - style->touch_padding.y;
bounds.w = r.w + 2 * style->touch_padding.x;
bounds.h = r.h + 2 * style->touch_padding.y;
return nk_button_behavior(state, bounds, in, behavior);
}
NK_LIB void
nk_draw_button_text(struct nk_command_buffer *out,
const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,
const struct nk_style_button *style, const char *txt, int len,
nk_flags text_alignment, const struct nk_user_font *font)
{
struct nk_text text;
const struct nk_style_item *background;
background = nk_draw_button(out, bounds, state, style);
/* select correct colors/images */
if (background->type == NK_STYLE_ITEM_COLOR)
text.background = background->data.color;
else text.background = style->text_background;
if (state & NK_WIDGET_STATE_HOVER)
text.text = style->text_hover;
else if (state & NK_WIDGET_STATE_ACTIVED)
text.text = style->text_active;
else text.text = style->text_normal;
text.padding = nk_vec2(0,0);
nk_widget_text(out, *content, txt, len, &text, text_alignment, font);
}
NK_LIB int
nk_do_button_text(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
const char *string, int len, nk_flags align, enum nk_button_behavior behavior,
const struct nk_style_button *style, const struct nk_input *in,
const struct nk_user_font *font)
{
struct nk_rect content;
int ret = nk_false;
NK_ASSERT(state);
NK_ASSERT(style);
NK_ASSERT(out);
NK_ASSERT(string);
NK_ASSERT(font);
if (!out || !style || !font || !string)
return nk_false;
ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return ret;
}
NK_LIB void
nk_draw_button_symbol(struct nk_command_buffer *out,
const struct nk_rect *bounds, const struct nk_rect *content,
nk_flags state, const struct nk_style_button *style,
enum nk_symbol_type type, const struct nk_user_font *font)
{
struct nk_color sym, bg;
const struct nk_style_item *background;
/* select correct colors/images */
background = nk_draw_button(out, bounds, state, style);
if (background->type == NK_STYLE_ITEM_COLOR)
bg = background->data.color;
else bg = style->text_background;
if (state & NK_WIDGET_STATE_HOVER)
sym = style->text_hover;
else if (state & NK_WIDGET_STATE_ACTIVED)
sym = style->text_active;
else sym = style->text_normal;
nk_draw_symbol(out, type, *content, bg, sym, 1, font);
}
NK_LIB int
nk_do_button_symbol(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
enum nk_symbol_type symbol, enum nk_button_behavior behavior,
const struct nk_style_button *style, const struct nk_input *in,
const struct nk_user_font *font)
{
int ret;
struct nk_rect content;
NK_ASSERT(state);
NK_ASSERT(style);
NK_ASSERT(font);
NK_ASSERT(out);
if (!out || !style || !font || !state)
return nk_false;
ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return ret;
}
NK_LIB void
nk_draw_button_image(struct nk_command_buffer *out,
const struct nk_rect *bounds, const struct nk_rect *content,
nk_flags state, const struct nk_style_button *style, const struct nk_image *img)
{
nk_draw_button(out, bounds, state, style);
nk_draw_image(out, *content, img, nk_white);
}
NK_LIB int
nk_do_button_image(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
struct nk_image img, enum nk_button_behavior b,
const struct nk_style_button *style, const struct nk_input *in)
{
int ret;
struct nk_rect content;
NK_ASSERT(state);
NK_ASSERT(style);
NK_ASSERT(out);
if (!out || !style || !state)
return nk_false;
ret = nk_do_button(state, out, bounds, style, in, b, &content);
content.x += style->image_padding.x;
content.y += style->image_padding.y;
content.w -= 2 * style->image_padding.x;
content.h -= 2 * style->image_padding.y;
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_button_image(out, &bounds, &content, *state, style, &img);
if (style->draw_end) style->draw_end(out, style->userdata);
return ret;
}
NK_LIB void
nk_draw_button_text_symbol(struct nk_command_buffer *out,
const struct nk_rect *bounds, const struct nk_rect *label,
const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,
const char *str, int len, enum nk_symbol_type type,
const struct nk_user_font *font)
{
struct nk_color sym;
struct nk_text text;
const struct nk_style_item *background;
/* select correct background colors/images */
background = nk_draw_button(out, bounds, state, style);
if (background->type == NK_STYLE_ITEM_COLOR)
text.background = background->data.color;
else text.background = style->text_background;
/* select correct text colors */
if (state & NK_WIDGET_STATE_HOVER) {
sym = style->text_hover;
text.text = style->text_hover;
} else if (state & NK_WIDGET_STATE_ACTIVED) {
sym = style->text_active;
text.text = style->text_active;
} else {
sym = style->text_normal;
text.text = style->text_normal;
}
text.padding = nk_vec2(0,0);
nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);
nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
}
NK_LIB int
nk_do_button_text_symbol(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
enum nk_symbol_type symbol, const char *str, int len, nk_flags align,
enum nk_button_behavior behavior, const struct nk_style_button *style,
const struct nk_user_font *font, const struct nk_input *in)
{
int ret;
struct nk_rect tri = {0,0,0,0};
struct nk_rect content;
NK_ASSERT(style);
NK_ASSERT(out);
NK_ASSERT(font);
if (!out || !style || !font)
return nk_false;
ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
tri.y = content.y + (content.h/2) - font->height/2;
tri.w = font->height; tri.h = font->height;
if (align & NK_TEXT_ALIGN_LEFT) {
tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);
tri.x = NK_MAX(tri.x, 0);
} else tri.x = content.x + 2 * style->padding.x;
/* draw button */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_button_text_symbol(out, &bounds, &content, &tri,
*state, style, str, len, symbol, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return ret;
}
NK_LIB void
nk_draw_button_text_image(struct nk_command_buffer *out,
const struct nk_rect *bounds, const struct nk_rect *label,
const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,
const char *str, int len, const struct nk_user_font *font,
const struct nk_image *img)
{
struct nk_text text;
const struct nk_style_item *background;
background = nk_draw_button(out, bounds, state, style);
/* select correct colors */
if (background->type == NK_STYLE_ITEM_COLOR)
text.background = background->data.color;
else text.background = style->text_background;
if (state & NK_WIDGET_STATE_HOVER)
text.text = style->text_hover;
else if (state & NK_WIDGET_STATE_ACTIVED)
text.text = style->text_active;
else text.text = style->text_normal;
text.padding = nk_vec2(0,0);
nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
nk_draw_image(out, *image, img, nk_white);
}
NK_LIB int
nk_do_button_text_image(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
struct nk_image img, const char* str, int len, nk_flags align,
enum nk_button_behavior behavior, const struct nk_style_button *style,
const struct nk_user_font *font, const struct nk_input *in)
{
int ret;
struct nk_rect icon;
struct nk_rect content;
NK_ASSERT(style);
NK_ASSERT(state);
NK_ASSERT(font);
NK_ASSERT(out);
if (!out || !font || !style || !str)
return nk_false;
ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
icon.y = bounds.y + style->padding.y;
icon.w = icon.h = bounds.h - 2 * style->padding.y;
if (align & NK_TEXT_ALIGN_LEFT) {
icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
icon.x = NK_MAX(icon.x, 0);
} else icon.x = bounds.x + 2 * style->padding.x;
icon.x += style->image_padding.x;
icon.y += style->image_padding.y;
icon.w -= 2 * style->image_padding.x;
icon.h -= 2 * style->image_padding.y;
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);
if (style->draw_end) style->draw_end(out, style->userdata);
return ret;
}
NK_API void
nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
{
NK_ASSERT(ctx);
if (!ctx) return;
ctx->button_behavior = behavior;
}
NK_API int
nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
{
struct nk_config_stack_button_behavior *button_stack;
struct nk_config_stack_button_behavior_element *element;
NK_ASSERT(ctx);
if (!ctx) return 0;
button_stack = &ctx->stacks.button_behaviors;
NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));
if (button_stack->head >= (int)NK_LEN(button_stack->elements))
return 0;
element = &button_stack->elements[button_stack->head++];
element->address = &ctx->button_behavior;
element->old_value = ctx->button_behavior;
ctx->button_behavior = behavior;
return 1;
}
NK_API int
nk_button_pop_behavior(struct nk_context *ctx)
{
struct nk_config_stack_button_behavior *button_stack;
struct nk_config_stack_button_behavior_element *element;
NK_ASSERT(ctx);
if (!ctx) return 0;
button_stack = &ctx->stacks.button_behaviors;
NK_ASSERT(button_stack->head > 0);
if (button_stack->head < 1)
return 0;
element = &button_stack->elements[--button_stack->head];
*element->address = element->old_value;
return 1;
}
NK_API int
nk_button_text_styled(struct nk_context *ctx,
const struct nk_style_button *style, const char *title, int len)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(style);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
title, len, style->text_alignment, ctx->button_behavior,
style, in, ctx->style.font);
}
NK_API int
nk_button_text(struct nk_context *ctx, const char *title, int len)
{
NK_ASSERT(ctx);
if (!ctx) return 0;
return nk_button_text_styled(ctx, &ctx->style.button, title, len);
}
NK_API int nk_button_label_styled(struct nk_context *ctx,
const struct nk_style_button *style, const char *title)
{
return nk_button_text_styled(ctx, style, title, nk_strlen(title));
}
NK_API int nk_button_label(struct nk_context *ctx, const char *title)
{
return nk_button_text(ctx, title, nk_strlen(title));
}
NK_API int
nk_button_color(struct nk_context *ctx, struct nk_color color)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_style_button button;
int ret = 0;
struct nk_rect bounds;
struct nk_rect content;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
button = ctx->style.button;
button.normal = nk_style_item_color(color);
button.hover = nk_style_item_color(color);
button.active = nk_style_item_color(color);
ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,
&button, in, ctx->button_behavior, &content);
nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);
return ret;
}
NK_API int
nk_button_symbol_styled(struct nk_context *ctx,
const struct nk_style_button *style, enum nk_symbol_type symbol)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,
symbol, ctx->button_behavior, style, in, ctx->style.font);
}
NK_API int
nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)
{
NK_ASSERT(ctx);
if (!ctx) return 0;
return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);
}
NK_API int
nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,
struct nk_image img)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,
img, ctx->button_behavior, style, in);
}
NK_API int
nk_button_image(struct nk_context *ctx, struct nk_image img)
{
NK_ASSERT(ctx);
if (!ctx) return 0;
return nk_button_image_styled(ctx, &ctx->style.button, img);
}
NK_API int
nk_button_symbol_text_styled(struct nk_context *ctx,
const struct nk_style_button *style, enum nk_symbol_type symbol,
const char *text, int len, nk_flags align)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
symbol, text, len, align, ctx->button_behavior,
style, ctx->style.font, in);
}
NK_API int
nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
const char* text, int len, nk_flags align)
{
NK_ASSERT(ctx);
if (!ctx) return 0;
return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);
}
NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
const char *label, nk_flags align)
{
return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);
}
NK_API int nk_button_symbol_label_styled(struct nk_context *ctx,
const struct nk_style_button *style, enum nk_symbol_type symbol,
const char *title, nk_flags align)
{
return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);
}
NK_API int
nk_button_image_text_styled(struct nk_context *ctx,
const struct nk_style_button *style, struct nk_image img, const char *text,
int len, nk_flags align)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
bounds, img, text, len, align, ctx->button_behavior,
style, ctx->style.font, in);
}
NK_API int
nk_button_image_text(struct nk_context *ctx, struct nk_image img,
const char *text, int len, nk_flags align)
{
return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);
}
NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img,
const char *label, nk_flags align)
{
return nk_button_image_text(ctx, img, label, nk_strlen(label), align);
}
NK_API int nk_button_image_label_styled(struct nk_context *ctx,
const struct nk_style_button *style, struct nk_image img,
const char *label, nk_flags text_alignment)
{
return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);
}

318
src/nuklear_chart.c Normal file
View File

@ -0,0 +1,318 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CHART
*
* ===============================================================*/
NK_API int
nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
struct nk_color color, struct nk_color highlight,
int count, float min_value, float max_value)
{
struct nk_window *win;
struct nk_chart *chart;
const struct nk_style *config;
const struct nk_style_chart *style;
const struct nk_style_item *background;
struct nk_rect bounds = {0, 0, 0, 0};
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return 0;
if (!nk_widget(&bounds, ctx)) {
chart = &ctx->current->layout->chart;
nk_zero(chart, sizeof(*chart));
return 0;
}
win = ctx->current;
config = &ctx->style;
chart = &win->layout->chart;
style = &config->chart;
/* setup basic generic chart */
nk_zero(chart, sizeof(*chart));
chart->x = bounds.x + style->padding.x;
chart->y = bounds.y + style->padding.y;
chart->w = bounds.w - 2 * style->padding.x;
chart->h = bounds.h - 2 * style->padding.y;
chart->w = NK_MAX(chart->w, 2 * style->padding.x);
chart->h = NK_MAX(chart->h, 2 * style->padding.y);
/* add first slot into chart */
{struct nk_chart_slot *slot = &chart->slots[chart->slot++];
slot->type = type;
slot->count = count;
slot->color = color;
slot->highlight = highlight;
slot->min = NK_MIN(min_value, max_value);
slot->max = NK_MAX(min_value, max_value);
slot->range = slot->max - slot->min;}
/* draw chart background */
background = &style->background;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
} else {
nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
style->rounding, style->background.data.color);
}
return 1;
}
NK_API int
nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
int count, float min_value, float max_value)
{
return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,
ctx->style.chart.selected_color, count, min_value, max_value);
}
NK_API void
nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
struct nk_color color, struct nk_color highlight,
int count, float min_value, float max_value)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
if (!ctx || !ctx->current || !ctx->current->layout) return;
if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
/* add another slot into the graph */
{struct nk_chart *chart = &ctx->current->layout->chart;
struct nk_chart_slot *slot = &chart->slots[chart->slot++];
slot->type = type;
slot->count = count;
slot->color = color;
slot->highlight = highlight;
slot->min = NK_MIN(min_value, max_value);
slot->max = NK_MAX(min_value, max_value);
slot->range = slot->max - slot->min;}
}
NK_API void
nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
int count, float min_value, float max_value)
{
nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,
ctx->style.chart.selected_color, count, min_value, max_value);
}
NK_INTERN nk_flags
nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
struct nk_chart *g, float value, int slot)
{
struct nk_panel *layout = win->layout;
const struct nk_input *i = &ctx->input;
struct nk_command_buffer *out = &win->buffer;
nk_flags ret = 0;
struct nk_vec2 cur;
struct nk_rect bounds;
struct nk_color color;
float step;
float range;
float ratio;
NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
step = g->w / (float)g->slots[slot].count;
range = g->slots[slot].max - g->slots[slot].min;
ratio = (value - g->slots[slot].min) / range;
if (g->slots[slot].index == 0) {
/* first data point does not have a connection */
g->slots[slot].last.x = g->x;
g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
bounds.x = g->slots[slot].last.x - 2;
bounds.y = g->slots[slot].last.y - 2;
bounds.w = bounds.h = 4;
color = g->slots[slot].color;
if (!(layout->flags & NK_WINDOW_ROM) &&
NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
color = g->slots[slot].highlight;
}
nk_fill_rect(out, bounds, 0, color);
g->slots[slot].index += 1;
return ret;
}
/* draw a line between the last data point and the new one */
color = g->slots[slot].color;
cur.x = g->x + (float)(step * (float)g->slots[slot].index);
cur.y = (g->y + g->h) - (ratio * (float)g->h);
nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
bounds.x = cur.x - 3;
bounds.y = cur.y - 3;
bounds.w = bounds.h = 6;
/* user selection of current data point */
if (!(layout->flags & NK_WINDOW_ROM)) {
if (nk_input_is_mouse_hovering_rect(i, bounds)) {
ret = NK_CHART_HOVERING;
ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
color = g->slots[slot].highlight;
}
}
nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
/* save current data point position */
g->slots[slot].last.x = cur.x;
g->slots[slot].last.y = cur.y;
g->slots[slot].index += 1;
return ret;
}
NK_INTERN nk_flags
nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
struct nk_chart *chart, float value, int slot)
{
struct nk_command_buffer *out = &win->buffer;
const struct nk_input *in = &ctx->input;
struct nk_panel *layout = win->layout;
float ratio;
nk_flags ret = 0;
struct nk_color color;
struct nk_rect item = {0,0,0,0};
NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
if (chart->slots[slot].index >= chart->slots[slot].count)
return nk_false;
if (chart->slots[slot].count) {
float padding = (float)(chart->slots[slot].count-1);
item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
}
/* calculate bounds of current bar chart entry */
color = chart->slots[slot].color;;
item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
if (value >= 0) {
ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
item.y = (chart->y + chart->h) - chart->h * ratio;
} else {
ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
}
item.x = chart->x + ((float)chart->slots[slot].index * item.w);
item.x = item.x + ((float)chart->slots[slot].index);
/* user chart bar selection */
if (!(layout->flags & NK_WINDOW_ROM) &&
NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
ret = NK_CHART_HOVERING;
ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
color = chart->slots[slot].highlight;
}
nk_fill_rect(out, item, 0, color);
chart->slots[slot].index += 1;
return ret;
}
NK_API nk_flags
nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
{
nk_flags flags;
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
NK_ASSERT(slot < ctx->current->layout->chart.slot);
if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
if (slot >= ctx->current->layout->chart.slot) return nk_false;
win = ctx->current;
if (win->layout->chart.slot < slot) return nk_false;
switch (win->layout->chart.slots[slot].type) {
case NK_CHART_LINES:
flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
case NK_CHART_COLUMN:
flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
default:
case NK_CHART_MAX:
flags = 0;
}
return flags;
}
NK_API nk_flags
nk_chart_push(struct nk_context *ctx, float value)
{
return nk_chart_push_slot(ctx, value, 0);
}
NK_API void
nk_chart_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_chart *chart;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return;
win = ctx->current;
chart = &win->layout->chart;
NK_MEMSET(chart, 0, sizeof(*chart));
return;
}
NK_API void
nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
int count, int offset)
{
int i = 0;
float min_value;
float max_value;
NK_ASSERT(ctx);
NK_ASSERT(values);
if (!ctx || !values || !count) return;
min_value = values[offset];
max_value = values[offset];
for (i = 0; i < count; ++i) {
min_value = NK_MIN(values[i + offset], min_value);
max_value = NK_MAX(values[i + offset], max_value);
}
if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
for (i = 0; i < count; ++i)
nk_chart_push(ctx, values[i + offset]);
nk_chart_end(ctx);
}
}
NK_API void
nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
float(*value_getter)(void* user, int index), int count, int offset)
{
int i = 0;
float min_value;
float max_value;
NK_ASSERT(ctx);
NK_ASSERT(value_getter);
if (!ctx || !value_getter || !count) return;
max_value = min_value = value_getter(userdata, offset);
for (i = 0; i < count; ++i) {
float value = value_getter(userdata, i + offset);
min_value = NK_MIN(value, min_value);
max_value = NK_MAX(value, max_value);
}
if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
for (i = 0; i < count; ++i)
nk_chart_push(ctx, value_getter(userdata, i + offset));
nk_chart_end(ctx);
}
}

414
src/nuklear_color.c Normal file
View File

@ -0,0 +1,414 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* COLOR
*
* ===============================================================*/
NK_INTERN int
nk_parse_hex(const char *p, int length)
{
int i = 0;
int len = 0;
while (len < length) {
i <<= 4;
if (p[len] >= 'a' && p[len] <= 'f')
i += ((p[len] - 'a') + 10);
else if (p[len] >= 'A' && p[len] <= 'F')
i += ((p[len] - 'A') + 10);
else i += (p[len] - '0');
len++;
}
return i;
}
NK_API struct nk_color
nk_rgba(int r, int g, int b, int a)
{
struct nk_color ret;
ret.r = (nk_byte)NK_CLAMP(0, r, 255);
ret.g = (nk_byte)NK_CLAMP(0, g, 255);
ret.b = (nk_byte)NK_CLAMP(0, b, 255);
ret.a = (nk_byte)NK_CLAMP(0, a, 255);
return ret;
}
NK_API struct nk_color
nk_rgb_hex(const char *rgb)
{
struct nk_color col;
const char *c = rgb;
if (*c == '#') c++;
col.r = (nk_byte)nk_parse_hex(c, 2);
col.g = (nk_byte)nk_parse_hex(c+2, 2);
col.b = (nk_byte)nk_parse_hex(c+4, 2);
col.a = 255;
return col;
}
NK_API struct nk_color
nk_rgba_hex(const char *rgb)
{
struct nk_color col;
const char *c = rgb;
if (*c == '#') c++;
col.r = (nk_byte)nk_parse_hex(c, 2);
col.g = (nk_byte)nk_parse_hex(c+2, 2);
col.b = (nk_byte)nk_parse_hex(c+4, 2);
col.a = (nk_byte)nk_parse_hex(c+6, 2);
return col;
}
NK_API void
nk_color_hex_rgba(char *output, struct nk_color col)
{
#define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
output[1] = (char)NK_TO_HEX((col.r & 0x0F));
output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
output[3] = (char)NK_TO_HEX((col.g & 0x0F));
output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
output[5] = (char)NK_TO_HEX((col.b & 0x0F));
output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);
output[7] = (char)NK_TO_HEX((col.a & 0x0F));
output[8] = '\0';
#undef NK_TO_HEX
}
NK_API void
nk_color_hex_rgb(char *output, struct nk_color col)
{
#define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
output[1] = (char)NK_TO_HEX((col.r & 0x0F));
output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
output[3] = (char)NK_TO_HEX((col.g & 0x0F));
output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
output[5] = (char)NK_TO_HEX((col.b & 0x0F));
output[6] = '\0';
#undef NK_TO_HEX
}
NK_API struct nk_color
nk_rgba_iv(const int *c)
{
return nk_rgba(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_color
nk_rgba_bv(const nk_byte *c)
{
return nk_rgba(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_color
nk_rgb(int r, int g, int b)
{
struct nk_color ret;
ret.r = (nk_byte)NK_CLAMP(0, r, 255);
ret.g = (nk_byte)NK_CLAMP(0, g, 255);
ret.b = (nk_byte)NK_CLAMP(0, b, 255);
ret.a = (nk_byte)255;
return ret;
}
NK_API struct nk_color
nk_rgb_iv(const int *c)
{
return nk_rgb(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_rgb_bv(const nk_byte* c)
{
return nk_rgb(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_rgba_u32(nk_uint in)
{
struct nk_color ret;
ret.r = (in & 0xFF);
ret.g = ((in >> 8) & 0xFF);
ret.b = ((in >> 16) & 0xFF);
ret.a = (nk_byte)((in >> 24) & 0xFF);
return ret;
}
NK_API struct nk_color
nk_rgba_f(float r, float g, float b, float a)
{
struct nk_color ret;
ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);
return ret;
}
NK_API struct nk_color
nk_rgba_fv(const float *c)
{
return nk_rgba_f(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_color
nk_rgba_cf(struct nk_colorf c)
{
return nk_rgba_f(c.r, c.g, c.b, c.a);
}
NK_API struct nk_color
nk_rgb_f(float r, float g, float b)
{
struct nk_color ret;
ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
ret.a = 255;
return ret;
}
NK_API struct nk_color
nk_rgb_fv(const float *c)
{
return nk_rgb_f(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_rgb_cf(struct nk_colorf c)
{
return nk_rgb_f(c.r, c.g, c.b);
}
NK_API struct nk_color
nk_hsv(int h, int s, int v)
{
return nk_hsva(h, s, v, 255);
}
NK_API struct nk_color
nk_hsv_iv(const int *c)
{
return nk_hsv(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_hsv_bv(const nk_byte *c)
{
return nk_hsv(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_hsv_f(float h, float s, float v)
{
return nk_hsva_f(h, s, v, 1.0f);
}
NK_API struct nk_color
nk_hsv_fv(const float *c)
{
return nk_hsv_f(c[0], c[1], c[2]);
}
NK_API struct nk_color
nk_hsva(int h, int s, int v, int a)
{
float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;
float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;
float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;
float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;
return nk_hsva_f(hf, sf, vf, af);
}
NK_API struct nk_color
nk_hsva_iv(const int *c)
{
return nk_hsva(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_color
nk_hsva_bv(const nk_byte *c)
{
return nk_hsva(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_colorf
nk_hsva_colorf(float h, float s, float v, float a)
{
int i;
float p, q, t, f;
struct nk_colorf out = {0,0,0,0};
if (s <= 0.0f) {
out.r = v; out.g = v; out.b = v; out.a = a;
return out;
}
h = h / (60.0f/360.0f);
i = (int)h;
f = h - (float)i;
p = v * (1.0f - s);
q = v * (1.0f - (s * f));
t = v * (1.0f - s * (1.0f - f));
switch (i) {
case 0: default: out.r = v; out.g = t; out.b = p; break;
case 1: out.r = q; out.g = v; out.b = p; break;
case 2: out.r = p; out.g = v; out.b = t; break;
case 3: out.r = p; out.g = q; out.b = v; break;
case 4: out.r = t; out.g = p; out.b = v; break;
case 5: out.r = v; out.g = p; out.b = q; break;}
out.a = a;
return out;
}
NK_API struct nk_colorf
nk_hsva_colorfv(float *c)
{
return nk_hsva_colorf(c[0], c[1], c[2], c[3]);
}
NK_API struct nk_color
nk_hsva_f(float h, float s, float v, float a)
{
struct nk_colorf c = nk_hsva_colorf(h, s, v, a);
return nk_rgba_f(c.r, c.g, c.b, c.a);
}
NK_API struct nk_color
nk_hsva_fv(const float *c)
{
return nk_hsva_f(c[0], c[1], c[2], c[3]);
}
NK_API nk_uint
nk_color_u32(struct nk_color in)
{
nk_uint out = (nk_uint)in.r;
out |= ((nk_uint)in.g << 8);
out |= ((nk_uint)in.b << 16);
out |= ((nk_uint)in.a << 24);
return out;
}
NK_API void
nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)
{
NK_STORAGE const float s = 1.0f/255.0f;
*r = (float)in.r * s;
*g = (float)in.g * s;
*b = (float)in.b * s;
*a = (float)in.a * s;
}
NK_API void
nk_color_fv(float *c, struct nk_color in)
{
nk_color_f(&c[0], &c[1], &c[2], &c[3], in);
}
NK_API struct nk_colorf
nk_color_cf(struct nk_color in)
{
struct nk_colorf o;
nk_color_f(&o.r, &o.g, &o.b, &o.a, in);
return o;
}
NK_API void
nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)
{
NK_STORAGE const double s = 1.0/255.0;
*r = (double)in.r * s;
*g = (double)in.g * s;
*b = (double)in.b * s;
*a = (double)in.a * s;
}
NK_API void
nk_color_dv(double *c, struct nk_color in)
{
nk_color_d(&c[0], &c[1], &c[2], &c[3], in);
}
NK_API void
nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)
{
float a;
nk_color_hsva_f(out_h, out_s, out_v, &a, in);
}
NK_API void
nk_color_hsv_fv(float *out, struct nk_color in)
{
float a;
nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);
}
NK_API void
nk_colorf_hsva_f(float *out_h, float *out_s,
float *out_v, float *out_a, struct nk_colorf in)
{
float chroma;
float K = 0.0f;
if (in.g < in.b) {
const float t = in.g; in.g = in.b; in.b = t;
K = -1.f;
}
if (in.r < in.g) {
const float t = in.r; in.r = in.g; in.g = t;
K = -2.f/6.0f - K;
}
chroma = in.r - ((in.g < in.b) ? in.g: in.b);
*out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f));
*out_s = chroma / (in.r + 1e-20f);
*out_v = in.r;
*out_a = in.a;
}
NK_API void
nk_colorf_hsva_fv(float *hsva, struct nk_colorf in)
{
nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in);
}
NK_API void
nk_color_hsva_f(float *out_h, float *out_s,
float *out_v, float *out_a, struct nk_color in)
{
struct nk_colorf col;
nk_color_f(&col.r,&col.g,&col.b,&col.a, in);
nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col);
}
NK_API void
nk_color_hsva_fv(float *out, struct nk_color in)
{
nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);
}
NK_API void
nk_color_hsva_i(int *out_h, int *out_s, int *out_v,
int *out_a, struct nk_color in)
{
float h,s,v,a;
nk_color_hsva_f(&h, &s, &v, &a, in);
*out_h = (nk_byte)(h * 255.0f);
*out_s = (nk_byte)(s * 255.0f);
*out_v = (nk_byte)(v * 255.0f);
*out_a = (nk_byte)(a * 255.0f);
}
NK_API void
nk_color_hsva_iv(int *out, struct nk_color in)
{
nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);
}
NK_API void
nk_color_hsva_bv(nk_byte *out, struct nk_color in)
{
int tmp[4];
nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
out[0] = (nk_byte)tmp[0];
out[1] = (nk_byte)tmp[1];
out[2] = (nk_byte)tmp[2];
out[3] = (nk_byte)tmp[3];
}
NK_API void
nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)
{
int tmp[4];
nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
*h = (nk_byte)tmp[0];
*s = (nk_byte)tmp[1];
*v = (nk_byte)tmp[2];
*a = (nk_byte)tmp[3];
}
NK_API void
nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)
{
int a;
nk_color_hsva_i(out_h, out_s, out_v, &a, in);
}
NK_API void
nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)
{
int tmp[4];
nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
*out_h = (nk_byte)tmp[0];
*out_s = (nk_byte)tmp[1];
*out_v = (nk_byte)tmp[2];
}
NK_API void
nk_color_hsv_iv(int *out, struct nk_color in)
{
nk_color_hsv_i(&out[0], &out[1], &out[2], in);
}
NK_API void
nk_color_hsv_bv(nk_byte *out, struct nk_color in)
{
int tmp[4];
nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);
out[0] = (nk_byte)tmp[0];
out[1] = (nk_byte)tmp[1];
out[2] = (nk_byte)tmp[2];
}

201
src/nuklear_color_picker.c Normal file
View File

@ -0,0 +1,201 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* COLOR PICKER
*
* ===============================================================*/
NK_LIB int
nk_color_picker_behavior(nk_flags *state,
const struct nk_rect *bounds, const struct nk_rect *matrix,
const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
struct nk_colorf *color, const struct nk_input *in)
{
float hsva[4];
int value_changed = 0;
int hsv_changed = 0;
NK_ASSERT(state);
NK_ASSERT(matrix);
NK_ASSERT(hue_bar);
NK_ASSERT(color);
/* color matrix */
nk_colorf_hsva_fv(hsva, *color);
if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {
hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));
hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));
value_changed = hsv_changed = 1;
}
/* hue bar */
if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {
hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));
value_changed = hsv_changed = 1;
}
/* alpha bar */
if (alpha_bar) {
if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {
hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));
value_changed = 1;
}
}
nk_widget_state_reset(state);
if (hsv_changed) {
*color = nk_hsva_colorfv(hsva);
*state = NK_WIDGET_STATE_ACTIVE;
}
if (value_changed) {
color->a = hsva[3];
*state = NK_WIDGET_STATE_ACTIVE;
}
/* set color picker widget state */
if (nk_input_is_mouse_hovering_rect(in, *bounds))
*state = NK_WIDGET_STATE_HOVERED;
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))
*state |= NK_WIDGET_STATE_LEFT;
return value_changed;
}
NK_LIB void
nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,
const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
struct nk_colorf col)
{
NK_STORAGE const struct nk_color black = {0,0,0,255};
NK_STORAGE const struct nk_color white = {255, 255, 255, 255};
NK_STORAGE const struct nk_color black_trans = {0,0,0,0};
const float crosshair_size = 7.0f;
struct nk_color temp;
float hsva[4];
float line_y;
int i;
NK_ASSERT(o);
NK_ASSERT(matrix);
NK_ASSERT(hue_bar);
/* draw hue bar */
nk_colorf_hsva_fv(hsva, col);
for (i = 0; i < 6; ++i) {
NK_GLOBAL const struct nk_color hue_colors[] = {
{255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255},
{0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255}
};
nk_fill_rect_multi_color(o,
nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,
hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],
hue_colors[i+1], hue_colors[i+1]);
}
line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);
nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,
line_y, 1, nk_rgb(255,255,255));
/* draw alpha bar */
if (alpha_bar) {
float alpha = NK_SATURATE(col.a);
line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f);
nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);
nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,
line_y, 1, nk_rgb(255,255,255));
}
/* draw color matrix */
temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);
nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);
nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);
/* draw cross-hair */
{struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];
p.x = (float)(int)(matrix->x + S * matrix->w);
p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);
nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);
nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);
nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);
nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}
}
NK_LIB int
nk_do_color_picker(nk_flags *state,
struct nk_command_buffer *out, struct nk_colorf *col,
enum nk_color_format fmt, struct nk_rect bounds,
struct nk_vec2 padding, const struct nk_input *in,
const struct nk_user_font *font)
{
int ret = 0;
struct nk_rect matrix;
struct nk_rect hue_bar;
struct nk_rect alpha_bar;
float bar_w;
NK_ASSERT(out);
NK_ASSERT(col);
NK_ASSERT(state);
NK_ASSERT(font);
if (!out || !col || !state || !font)
return ret;
bar_w = font->height;
bounds.x += padding.x;
bounds.y += padding.x;
bounds.w -= 2 * padding.x;
bounds.h -= 2 * padding.y;
matrix.x = bounds.x;
matrix.y = bounds.y;
matrix.h = bounds.h;
matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);
hue_bar.w = bar_w;
hue_bar.y = bounds.y;
hue_bar.h = matrix.h;
hue_bar.x = matrix.x + matrix.w + padding.x;
alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;
alpha_bar.y = bounds.y;
alpha_bar.w = bar_w;
alpha_bar.h = matrix.h;
ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,
(fmt == NK_RGBA) ? &alpha_bar:0, col, in);
nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col);
return ret;
}
NK_API int
nk_color_pick(struct nk_context * ctx, struct nk_colorf *color,
enum nk_color_format fmt)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_style *config;
const struct nk_input *in;
enum nk_widget_layout_states state;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(color);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !color)
return 0;
win = ctx->current;
config = &ctx->style;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,
nk_vec2(0,0), in, config->font);
}
NK_API struct nk_colorf
nk_color_picker(struct nk_context *ctx, struct nk_colorf color,
enum nk_color_format fmt)
{
nk_color_pick(ctx, &color, fmt);
return color;
}

763
src/nuklear_combo.c Normal file
View File

@ -0,0 +1,763 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* COMBO
*
* ===============================================================*/
NK_INTERN int
nk_combo_begin(struct nk_context *ctx, struct nk_window *win,
struct nk_vec2 size, int is_clicked, struct nk_rect header)
{
struct nk_window *popup;
int is_open = 0;
int is_active = 0;
struct nk_rect body;
nk_hash hash;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
popup = win->popup.win;
body.x = header.x;
body.w = size.x;
body.y = header.y + header.h-ctx->style.window.combo_border;
body.h = size.y;
hash = win->popup.combo_count++;
is_open = (popup) ? nk_true:nk_false;
is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);
if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
(!is_open && !is_active && !is_clicked)) return 0;
if (!nk_nonblock_begin(ctx, 0, body,
(is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;
win->popup.type = NK_PANEL_COMBO;
win->popup.name = hash;
return 1;
}
NK_API int
nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,
struct nk_vec2 size)
{
const struct nk_input *in;
struct nk_window *win;
struct nk_style *style;
enum nk_widget_layout_states s;
int is_clicked = nk_false;
struct nk_rect header;
const struct nk_style_item *background;
struct nk_text text;
NK_ASSERT(ctx);
NK_ASSERT(selected);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !selected)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (s == NK_WIDGET_INVALID)
return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
background = &style->combo.active;
text.text = style->combo.label_active;
} else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
background = &style->combo.hover;
text.text = style->combo.label_hover;
} else {
background = &style->combo.normal;
text.text = style->combo.label_normal;
}
if (background->type == NK_STYLE_ITEM_IMAGE) {
text.background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
text.background = background->data.color;
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
/* print currently selected text item */
struct nk_rect label;
struct nk_rect button;
struct nk_rect content;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
/* draw selected label */
text.padding = nk_vec2(0,0);
label.x = header.x + style->combo.content_padding.x;
label.y = header.y + style->combo.content_padding.y;
label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;;
label.h = header.h - 2 * style->combo.content_padding.y;
nk_widget_text(&win->buffer, label, selected, len, &text,
NK_TEXT_LEFT, ctx->style.font);
/* draw open/close button */
nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)
{
return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);
}
NK_API int
nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_style *style;
const struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
enum nk_widget_layout_states s;
const struct nk_style_item *background;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (s == NK_WIDGET_INVALID)
return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
background = &style->combo.active;
else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
background = &style->combo.hover;
else background = &style->combo.normal;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(&win->buffer, header, &background->data.image,nk_white);
} else {
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
struct nk_rect content;
struct nk_rect button;
struct nk_rect bounds;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
/* draw color */
bounds.h = header.h - 4 * style->combo.content_padding.y;
bounds.y = header.y + 2 * style->combo.content_padding.y;
bounds.x = header.x + 2 * style->combo.content_padding.x;
bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;
nk_fill_rect(&win->buffer, bounds, 0, color);
/* draw open/close button */
nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_style *style;
const struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
enum nk_widget_layout_states s;
const struct nk_style_item *background;
struct nk_color sym_background;
struct nk_color symbol_color;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (s == NK_WIDGET_INVALID)
return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
background = &style->combo.active;
symbol_color = style->combo.symbol_active;
} else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
background = &style->combo.hover;
symbol_color = style->combo.symbol_hover;
} else {
background = &style->combo.normal;
symbol_color = style->combo.symbol_hover;
}
if (background->type == NK_STYLE_ITEM_IMAGE) {
sym_background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
sym_background = background->data.color;
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
struct nk_rect bounds = {0,0,0,0};
struct nk_rect content;
struct nk_rect button;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
/* draw symbol */
bounds.h = header.h - 2 * style->combo.content_padding.y;
bounds.y = header.y + style->combo.content_padding.y;
bounds.x = header.x + style->combo.content_padding.x;
bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,
1.0f, style->font);
/* draw open/close button */
nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,
enum nk_symbol_type symbol, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_style *style;
struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
enum nk_widget_layout_states s;
const struct nk_style_item *background;
struct nk_color symbol_color;
struct nk_text text;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (!s) return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
background = &style->combo.active;
symbol_color = style->combo.symbol_active;
text.text = style->combo.label_active;
} else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
background = &style->combo.hover;
symbol_color = style->combo.symbol_hover;
text.text = style->combo.label_hover;
} else {
background = &style->combo.normal;
symbol_color = style->combo.symbol_normal;
text.text = style->combo.label_normal;
}
if (background->type == NK_STYLE_ITEM_IMAGE) {
text.background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
text.background = background->data.color;
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
struct nk_rect content;
struct nk_rect button;
struct nk_rect label;
struct nk_rect image;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
/* draw symbol */
image.x = header.x + style->combo.content_padding.x;
image.y = header.y + style->combo.content_padding.y;
image.h = header.h - 2 * style->combo.content_padding.y;
image.w = image.h;
nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,
1.0f, style->font);
/* draw label */
text.padding = nk_vec2(0,0);
label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
label.y = header.y + style->combo.content_padding.y;
label.w = (button.x - style->combo.content_padding.x) - label.x;
label.h = header.h - 2 * style->combo.content_padding.y;
nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_style *style;
const struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
enum nk_widget_layout_states s;
const struct nk_style_item *background;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (s == NK_WIDGET_INVALID)
return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
background = &style->combo.active;
else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
background = &style->combo.hover;
else background = &style->combo.normal;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
struct nk_rect bounds = {0,0,0,0};
struct nk_rect content;
struct nk_rect button;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
/* draw image */
bounds.h = header.h - 2 * style->combo.content_padding.y;
bounds.y = header.y + style->combo.content_padding.y;
bounds.x = header.x + style->combo.content_padding.x;
bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
nk_draw_image(&win->buffer, bounds, &img, nk_white);
/* draw open/close button */
nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,
struct nk_image img, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_style *style;
struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
enum nk_widget_layout_states s;
const struct nk_style_item *background;
struct nk_text text;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
s = nk_widget(&header, ctx);
if (!s) return 0;
in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
is_clicked = nk_true;
/* draw combo box header background and border */
if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
background = &style->combo.active;
text.text = style->combo.label_active;
} else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
background = &style->combo.hover;
text.text = style->combo.label_hover;
} else {
background = &style->combo.normal;
text.text = style->combo.label_normal;
}
if (background->type == NK_STYLE_ITEM_IMAGE) {
text.background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
text.background = background->data.color;
nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
}
{
struct nk_rect content;
struct nk_rect button;
struct nk_rect label;
struct nk_rect image;
enum nk_symbol_type sym;
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
sym = style->combo.sym_hover;
else if (is_clicked)
sym = style->combo.sym_active;
else sym = style->combo.sym_normal;
/* calculate button */
button.w = header.h - 2 * style->combo.button_padding.y;
button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
button.y = header.y + style->combo.button_padding.y;
button.h = button.w;
content.x = button.x + style->combo.button.padding.x;
content.y = button.y + style->combo.button.padding.y;
content.w = button.w - 2 * style->combo.button.padding.x;
content.h = button.h - 2 * style->combo.button.padding.y;
nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
&ctx->style.combo.button, sym, style->font);
/* draw image */
image.x = header.x + style->combo.content_padding.x;
image.y = header.y + style->combo.content_padding.y;
image.h = header.h - 2 * style->combo.content_padding.y;
image.w = image.h;
nk_draw_image(&win->buffer, image, &img, nk_white);
/* draw label */
text.padding = nk_vec2(0,0);
label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
label.y = header.y + style->combo.content_padding.y;
label.w = (button.x - style->combo.content_padding.x) - label.x;
label.h = header.h - 2 * style->combo.content_padding.y;
nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
}
return nk_combo_begin(ctx, win, size, is_clicked, header);
}
NK_API int
nk_combo_begin_symbol_label(struct nk_context *ctx,
const char *selected, enum nk_symbol_type type, struct nk_vec2 size)
{
return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);
}
NK_API int
nk_combo_begin_image_label(struct nk_context *ctx,
const char *selected, struct nk_image img, struct nk_vec2 size)
{
return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);
}
NK_API int
nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)
{
return nk_contextual_item_text(ctx, text, len, align);
}
NK_API int
nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)
{
return nk_contextual_item_label(ctx, label, align);
}
NK_API int
nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,
int len, nk_flags alignment)
{
return nk_contextual_item_image_text(ctx, img, text, len, alignment);
}
NK_API int
nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,
const char *text, nk_flags alignment)
{
return nk_contextual_item_image_label(ctx, img, text, alignment);
}
NK_API int
nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
const char *text, int len, nk_flags alignment)
{
return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);
}
NK_API int
nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
const char *label, nk_flags alignment)
{
return nk_contextual_item_symbol_label(ctx, sym, label, alignment);
}
NK_API void nk_combo_end(struct nk_context *ctx)
{
nk_contextual_end(ctx);
}
NK_API void nk_combo_close(struct nk_context *ctx)
{
nk_contextual_close(ctx);
}
NK_API int
nk_combo(struct nk_context *ctx, const char **items, int count,
int selected, int item_height, struct nk_vec2 size)
{
int i = 0;
int max_height;
struct nk_vec2 item_spacing;
struct nk_vec2 window_padding;
NK_ASSERT(ctx);
NK_ASSERT(items);
NK_ASSERT(ctx->current);
if (!ctx || !items ||!count)
return selected;
item_spacing = ctx->style.window.spacing;
window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
max_height = count * item_height + count * (int)item_spacing.y;
max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
size.y = NK_MIN(size.y, (float)max_height);
if (nk_combo_begin_label(ctx, items[selected], size)) {
nk_layout_row_dynamic(ctx, (float)item_height, 1);
for (i = 0; i < count; ++i) {
if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
selected = i;
}
nk_combo_end(ctx);
}
return selected;
}
NK_API int
nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,
int separator, int selected, int count, int item_height, struct nk_vec2 size)
{
int i;
int max_height;
struct nk_vec2 item_spacing;
struct nk_vec2 window_padding;
const char *current_item;
const char *iter;
int length = 0;
NK_ASSERT(ctx);
NK_ASSERT(items_separated_by_separator);
if (!ctx || !items_separated_by_separator)
return selected;
/* calculate popup window */
item_spacing = ctx->style.window.spacing;
window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
max_height = count * item_height + count * (int)item_spacing.y;
max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
size.y = NK_MIN(size.y, (float)max_height);
/* find selected item */
current_item = items_separated_by_separator;
for (i = 0; i < count; ++i) {
iter = current_item;
while (*iter && *iter != separator) iter++;
length = (int)(iter - current_item);
if (i == selected) break;
current_item = iter + 1;
}
if (nk_combo_begin_text(ctx, current_item, length, size)) {
current_item = items_separated_by_separator;
nk_layout_row_dynamic(ctx, (float)item_height, 1);
for (i = 0; i < count; ++i) {
iter = current_item;
while (*iter && *iter != separator) iter++;
length = (int)(iter - current_item);
if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))
selected = i;
current_item = current_item + length + 1;
}
nk_combo_end(ctx);
}
return selected;
}
NK_API int
nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,
int selected, int count, int item_height, struct nk_vec2 size)
{
return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);
}
NK_API int
nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),
void *userdata, int selected, int count, int item_height, struct nk_vec2 size)
{
int i;
int max_height;
struct nk_vec2 item_spacing;
struct nk_vec2 window_padding;
const char *item;
NK_ASSERT(ctx);
NK_ASSERT(item_getter);
if (!ctx || !item_getter)
return selected;
/* calculate popup window */
item_spacing = ctx->style.window.spacing;
window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
max_height = count * item_height + count * (int)item_spacing.y;
max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
size.y = NK_MIN(size.y, (float)max_height);
item_getter(userdata, selected, &item);
if (nk_combo_begin_label(ctx, item, size)) {
nk_layout_row_dynamic(ctx, (float)item_height, 1);
for (i = 0; i < count; ++i) {
item_getter(userdata, i, &item);
if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))
selected = i;
}
nk_combo_end(ctx);
} return selected;
}
NK_API void
nk_combobox(struct nk_context *ctx, const char **items, int count,
int *selected, int item_height, struct nk_vec2 size)
{
*selected = nk_combo(ctx, items, count, *selected, item_height, size);
}
NK_API void
nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,
int *selected, int count, int item_height, struct nk_vec2 size)
{
*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);
}
NK_API void
nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,
int separator,int *selected, int count, int item_height, struct nk_vec2 size)
{
*selected = nk_combo_separator(ctx, items_separated_by_separator, separator,
*selected, count, item_height, size);
}
NK_API void
nk_combobox_callback(struct nk_context *ctx,
void(*item_getter)(void* data, int id, const char **out_text),
void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)
{
*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);
}

344
src/nuklear_context.c Normal file
View File

@ -0,0 +1,344 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CONTEXT
*
* ===============================================================*/
NK_INTERN void
nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
{
NK_ASSERT(ctx);
if (!ctx) return;
nk_zero_struct(*ctx);
nk_style_default(ctx);
ctx->seq = 1;
if (font) ctx->style.font = font;
#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
nk_draw_list_init(&ctx->draw_list);
#endif
}
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_API int
nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
{
struct nk_allocator alloc;
alloc.userdata.ptr = 0;
alloc.alloc = nk_malloc;
alloc.free = nk_mfree;
return nk_init(ctx, &alloc, font);
}
#endif
NK_API int
nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
const struct nk_user_font *font)
{
NK_ASSERT(memory);
if (!memory) return 0;
nk_setup(ctx, font);
nk_buffer_init_fixed(&ctx->memory, memory, size);
ctx->use_pool = nk_false;
return 1;
}
NK_API int
nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
struct nk_buffer *pool, const struct nk_user_font *font)
{
NK_ASSERT(cmds);
NK_ASSERT(pool);
if (!cmds || !pool) return 0;
nk_setup(ctx, font);
ctx->memory = *cmds;
if (pool->type == NK_BUFFER_FIXED) {
/* take memory from buffer and alloc fixed pool */
nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
} else {
/* create dynamic pool from buffer allocator */
struct nk_allocator *alloc = &pool->pool;
nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
}
ctx->use_pool = nk_true;
return 1;
}
NK_API int
nk_init(struct nk_context *ctx, struct nk_allocator *alloc,
const struct nk_user_font *font)
{
NK_ASSERT(alloc);
if (!alloc) return 0;
nk_setup(ctx, font);
nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
ctx->use_pool = nk_true;
return 1;
}
#ifdef NK_INCLUDE_COMMAND_USERDATA
NK_API void
nk_set_user_data(struct nk_context *ctx, nk_handle handle)
{
if (!ctx) return;
ctx->userdata = handle;
if (ctx->current)
ctx->current->buffer.userdata = handle;
}
#endif
NK_API void
nk_free(struct nk_context *ctx)
{
NK_ASSERT(ctx);
if (!ctx) return;
nk_buffer_free(&ctx->memory);
if (ctx->use_pool)
nk_pool_free(&ctx->pool);
nk_zero(&ctx->input, sizeof(ctx->input));
nk_zero(&ctx->style, sizeof(ctx->style));
nk_zero(&ctx->memory, sizeof(ctx->memory));
ctx->seq = 0;
ctx->build = 0;
ctx->begin = 0;
ctx->end = 0;
ctx->active = 0;
ctx->current = 0;
ctx->freelist = 0;
ctx->count = 0;
}
NK_API void
nk_clear(struct nk_context *ctx)
{
struct nk_window *iter;
struct nk_window *next;
NK_ASSERT(ctx);
if (!ctx) return;
if (ctx->use_pool)
nk_buffer_clear(&ctx->memory);
else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
ctx->build = 0;
ctx->memory.calls = 0;
ctx->last_widget_state = 0;
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
/* garbage collector */
iter = ctx->begin;
while (iter) {
/* make sure valid minimized windows do not get removed */
if ((iter->flags & NK_WINDOW_MINIMIZED) &&
!(iter->flags & NK_WINDOW_CLOSED) &&
iter->seq == ctx->seq) {
iter = iter->next;
continue;
}
/* remove hotness from hidden or closed windows*/
if (((iter->flags & NK_WINDOW_HIDDEN) ||
(iter->flags & NK_WINDOW_CLOSED)) &&
iter == ctx->active) {
ctx->active = iter->prev;
ctx->end = iter->prev;
if (!ctx->end)
ctx->begin = 0;
if (ctx->active)
ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
}
/* free unused popup windows */
if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
nk_free_window(ctx, iter->popup.win);
iter->popup.win = 0;
}
/* remove unused window state tables */
{struct nk_table *n, *it = iter->tables;
while (it) {
n = it->next;
if (it->seq != ctx->seq) {
nk_remove_table(iter, it);
nk_zero(it, sizeof(union nk_page_data));
nk_free_table(ctx, it);
if (it == iter->tables)
iter->tables = n;
} it = n;
}}
/* window itself is not used anymore so free */
if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
next = iter->next;
nk_remove_window(ctx, iter);
nk_free_window(ctx, iter);
iter = next;
} else iter = iter->next;
}
ctx->seq++;
}
NK_LIB void
nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
{
NK_ASSERT(ctx);
NK_ASSERT(buffer);
if (!ctx || !buffer) return;
buffer->begin = ctx->memory.allocated;
buffer->end = buffer->begin;
buffer->last = buffer->begin;
buffer->clip = nk_null_rect;
}
NK_LIB void
nk_start(struct nk_context *ctx, struct nk_window *win)
{
NK_ASSERT(ctx);
NK_ASSERT(win);
nk_start_buffer(ctx, &win->buffer);
}
NK_LIB void
nk_start_popup(struct nk_context *ctx, struct nk_window *win)
{
struct nk_popup_buffer *buf;
NK_ASSERT(ctx);
NK_ASSERT(win);
if (!ctx || !win) return;
/* save buffer fill state for popup */
buf = &win->popup.buf;
buf->begin = win->buffer.end;
buf->end = win->buffer.end;
buf->parent = win->buffer.last;
buf->last = buf->begin;
buf->active = nk_true;
}
NK_LIB void
nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
{
struct nk_popup_buffer *buf;
NK_ASSERT(ctx);
NK_ASSERT(win);
if (!ctx || !win) return;
buf = &win->popup.buf;
buf->last = win->buffer.last;
buf->end = win->buffer.end;
}
NK_LIB void
nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
{
NK_ASSERT(ctx);
NK_ASSERT(buffer);
if (!ctx || !buffer) return;
buffer->end = ctx->memory.allocated;
}
NK_LIB void
nk_finish(struct nk_context *ctx, struct nk_window *win)
{
struct nk_popup_buffer *buf;
struct nk_command *parent_last;
void *memory;
NK_ASSERT(ctx);
NK_ASSERT(win);
if (!ctx || !win) return;
nk_finish_buffer(ctx, &win->buffer);
if (!win->popup.buf.active) return;
buf = &win->popup.buf;
memory = ctx->memory.memory.ptr;
parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
parent_last->next = buf->end;
}
NK_LIB void
nk_build(struct nk_context *ctx)
{
struct nk_window *it = 0;
struct nk_command *cmd = 0;
nk_byte *buffer = 0;
/* draw cursor overlay */
if (!ctx->style.cursor_active)
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
struct nk_rect mouse_bounds;
const struct nk_cursor *cursor = ctx->style.cursor_active;
nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
nk_start_buffer(ctx, &ctx->overlay);
mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
mouse_bounds.w = cursor->size.x;
mouse_bounds.h = cursor->size.y;
nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
nk_finish_buffer(ctx, &ctx->overlay);
}
/* build one big draw command list out of all window buffers */
it = ctx->begin;
buffer = (nk_byte*)ctx->memory.memory.ptr;
while (it != 0) {
struct nk_window *next = it->next;
if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||
it->seq != ctx->seq)
goto cont;
cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);
while (next && ((next->buffer.last == next->buffer.begin) ||
(next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))
next = next->next; /* skip empty command buffers */
if (next) cmd->next = next->buffer.begin;
cont: it = next;
}
/* append all popup draw commands into lists */
it = ctx->begin;
while (it != 0) {
struct nk_window *next = it->next;
struct nk_popup_buffer *buf;
if (!it->popup.buf.active)
goto skip;
buf = &it->popup.buf;
cmd->next = buf->begin;
cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
buf->active = nk_false;
skip: it = next;
}
if (cmd) {
/* append overlay commands */
if (ctx->overlay.end != ctx->overlay.begin)
cmd->next = ctx->overlay.begin;
else cmd->next = ctx->memory.allocated;
}
}
NK_API const struct nk_command*
nk__begin(struct nk_context *ctx)
{
struct nk_window *iter;
nk_byte *buffer;
NK_ASSERT(ctx);
if (!ctx) return 0;
if (!ctx->count) return 0;
buffer = (nk_byte*)ctx->memory.memory.ptr;
if (!ctx->build) {
nk_build(ctx);
ctx->build = nk_true;
}
iter = ctx->begin;
while (iter && ((iter->buffer.begin == iter->buffer.end) ||
(iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))
iter = iter->next;
if (!iter) return 0;
return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
}
NK_API const struct nk_command*
nk__next(struct nk_context *ctx, const struct nk_command *cmd)
{
nk_byte *buffer;
const struct nk_command *next;
NK_ASSERT(ctx);
if (!ctx || !cmd || !ctx->count) return 0;
if (cmd->next >= ctx->memory.allocated) return 0;
buffer = (nk_byte*)ctx->memory.memory.ptr;
next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
return next;
}

217
src/nuklear_contextual.c Normal file
View File

@ -0,0 +1,217 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CONTEXTUAL
*
* ===============================================================*/
NK_API int
nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,
struct nk_rect trigger_bounds)
{
struct nk_window *win;
struct nk_window *popup;
struct nk_rect body;
NK_STORAGE const struct nk_rect null_rect = {0,0,0,0};
int is_clicked = 0;
int is_active = 0;
int is_open = 0;
int ret = 0;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
++win->popup.con_count;
/* check if currently active contextual is active */
popup = win->popup.win;
is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);
is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds);
if (win->popup.active_con && win->popup.con_count != win->popup.active_con)
return 0;
if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked))
return 0;
/* calculate contextual position on click */
win->popup.active_con = win->popup.con_count;
if (is_clicked) {
body.x = ctx->input.mouse.pos.x;
body.y = ctx->input.mouse.pos.y;
} else {
body.x = popup->bounds.x;
body.y = popup->bounds.y;
}
body.w = size.x;
body.h = size.y;
/* start nonblocking contextual popup */
ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body,
null_rect, NK_PANEL_CONTEXTUAL);
if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;
else {
win->popup.active_con = 0;
if (win->popup.win)
win->popup.win->flags = 0;
}
return ret;
}
NK_API int
nk_contextual_item_text(struct nk_context *ctx, const char *text, int len,
nk_flags alignment)
{
struct nk_window *win;
const struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
if (!state) return nk_false;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {
nk_contextual_close(ctx);
return nk_true;
}
return nk_false;
}
NK_API int
nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)
{
return nk_contextual_item_text(ctx, label, nk_strlen(label), align);
}
NK_API int
nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,
const char *text, int len, nk_flags align)
{
struct nk_window *win;
const struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
if (!state) return nk_false;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,
img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){
nk_contextual_close(ctx);
return nk_true;
}
return nk_false;
}
NK_API int
nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,
const char *label, nk_flags align)
{
return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);
}
NK_API int
nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
const char *text, int len, nk_flags align)
{
struct nk_window *win;
const struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
if (!state) return nk_false;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {
nk_contextual_close(ctx);
return nk_true;
}
return nk_false;
}
NK_API int
nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
const char *text, nk_flags align)
{
return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);
}
NK_API void
nk_contextual_close(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return;
nk_popup_close(ctx);
}
NK_API void
nk_contextual_end(struct nk_context *ctx)
{
struct nk_window *popup;
struct nk_panel *panel;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return;
popup = ctx->current;
panel = popup->layout;
NK_ASSERT(popup->parent);
NK_ASSERT(panel->type & NK_PANEL_SET_POPUP);
if (panel->flags & NK_WINDOW_DYNAMIC) {
/* Close behavior
This is a bit of a hack solution since we do not know before we end our popup
how big it will be. We therefore do not directly know when a
click outside the non-blocking popup must close it at that direct frame.
Instead it will be closed in the next frame.*/
struct nk_rect body = {0,0,0,0};
if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {
struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);
body = panel->bounds;
body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);
body.h = (panel->bounds.y + panel->bounds.h) - body.y;
}
{int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
if (pressed && in_body)
popup->flags |= NK_WINDOW_HIDDEN;
}
}
if (popup->flags & NK_WINDOW_HIDDEN)
popup->seq = 0;
nk_popup_end(ctx);
return;
}

481
src/nuklear_draw.c Normal file
View File

@ -0,0 +1,481 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* DRAW
*
* ===============================================================*/
NK_LIB void
nk_command_buffer_init(struct nk_command_buffer *cb,
struct nk_buffer *b, enum nk_command_clipping clip)
{
NK_ASSERT(cb);
NK_ASSERT(b);
if (!cb || !b) return;
cb->base = b;
cb->use_clipping = (int)clip;
cb->begin = b->allocated;
cb->end = b->allocated;
cb->last = b->allocated;
}
NK_LIB void
nk_command_buffer_reset(struct nk_command_buffer *b)
{
NK_ASSERT(b);
if (!b) return;
b->begin = 0;
b->end = 0;
b->last = 0;
b->clip = nk_null_rect;
#ifdef NK_INCLUDE_COMMAND_USERDATA
b->userdata.ptr = 0;
#endif
}
NK_LIB void*
nk_command_buffer_push(struct nk_command_buffer* b,
enum nk_command_type t, nk_size size)
{
NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);
struct nk_command *cmd;
nk_size alignment;
void *unaligned;
void *memory;
NK_ASSERT(b);
NK_ASSERT(b->base);
if (!b) return 0;
cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);
if (!cmd) return 0;
/* make sure the offset to the next command is aligned */
b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);
unaligned = (nk_byte*)cmd + size;
memory = NK_ALIGN_PTR(unaligned, align);
alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
#ifdef NK_ZERO_COMMAND_MEMORY
NK_MEMSET(cmd, 0, size + alignment);
#endif
cmd->type = t;
cmd->next = b->base->allocated + alignment;
#ifdef NK_INCLUDE_COMMAND_USERDATA
cmd->userdata = b->userdata;
#endif
b->end = cmd->next;
return cmd;
}
NK_API void
nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)
{
struct nk_command_scissor *cmd;
NK_ASSERT(b);
if (!b) return;
b->clip.x = r.x;
b->clip.y = r.y;
b->clip.w = r.w;
b->clip.h = r.h;
cmd = (struct nk_command_scissor*)
nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));
if (!cmd) return;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)NK_MAX(0, r.w);
cmd->h = (unsigned short)NK_MAX(0, r.h);
}
NK_API void
nk_stroke_line(struct nk_command_buffer *b, float x0, float y0,
float x1, float y1, float line_thickness, struct nk_color c)
{
struct nk_command_line *cmd;
NK_ASSERT(b);
if (!b || line_thickness <= 0) return;
cmd = (struct nk_command_line*)
nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));
if (!cmd) return;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->begin.x = (short)x0;
cmd->begin.y = (short)y0;
cmd->end.x = (short)x1;
cmd->end.y = (short)y1;
cmd->color = c;
}
NK_API void
nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,
float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,
float bx, float by, float line_thickness, struct nk_color col)
{
struct nk_command_curve *cmd;
NK_ASSERT(b);
if (!b || col.a == 0 || line_thickness <= 0) return;
cmd = (struct nk_command_curve*)
nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));
if (!cmd) return;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->begin.x = (short)ax;
cmd->begin.y = (short)ay;
cmd->ctrl[0].x = (short)ctrl0x;
cmd->ctrl[0].y = (short)ctrl0y;
cmd->ctrl[1].x = (short)ctrl1x;
cmd->ctrl[1].y = (short)ctrl1y;
cmd->end.x = (short)bx;
cmd->end.y = (short)by;
cmd->color = col;
}
NK_API void
nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,
float rounding, float line_thickness, struct nk_color c)
{
struct nk_command_rect *cmd;
NK_ASSERT(b);
if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
clip->x, clip->y, clip->w, clip->h)) return;
}
cmd = (struct nk_command_rect*)
nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));
if (!cmd) return;
cmd->rounding = (unsigned short)rounding;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->x = (short)rect.x;
cmd->y = (short)rect.y;
cmd->w = (unsigned short)NK_MAX(0, rect.w);
cmd->h = (unsigned short)NK_MAX(0, rect.h);
cmd->color = c;
}
NK_API void
nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,
float rounding, struct nk_color c)
{
struct nk_command_rect_filled *cmd;
NK_ASSERT(b);
if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
clip->x, clip->y, clip->w, clip->h)) return;
}
cmd = (struct nk_command_rect_filled*)
nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));
if (!cmd) return;
cmd->rounding = (unsigned short)rounding;
cmd->x = (short)rect.x;
cmd->y = (short)rect.y;
cmd->w = (unsigned short)NK_MAX(0, rect.w);
cmd->h = (unsigned short)NK_MAX(0, rect.h);
cmd->color = c;
}
NK_API void
nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,
struct nk_color left, struct nk_color top, struct nk_color right,
struct nk_color bottom)
{
struct nk_command_rect_multi_color *cmd;
NK_ASSERT(b);
if (!b || rect.w == 0 || rect.h == 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
clip->x, clip->y, clip->w, clip->h)) return;
}
cmd = (struct nk_command_rect_multi_color*)
nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));
if (!cmd) return;
cmd->x = (short)rect.x;
cmd->y = (short)rect.y;
cmd->w = (unsigned short)NK_MAX(0, rect.w);
cmd->h = (unsigned short)NK_MAX(0, rect.h);
cmd->left = left;
cmd->top = top;
cmd->right = right;
cmd->bottom = bottom;
}
NK_API void
nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,
float line_thickness, struct nk_color c)
{
struct nk_command_circle *cmd;
if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
return;
}
cmd = (struct nk_command_circle*)
nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));
if (!cmd) return;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)NK_MAX(r.w, 0);
cmd->h = (unsigned short)NK_MAX(r.h, 0);
cmd->color = c;
}
NK_API void
nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)
{
struct nk_command_circle_filled *cmd;
NK_ASSERT(b);
if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
return;
}
cmd = (struct nk_command_circle_filled*)
nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));
if (!cmd) return;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)NK_MAX(r.w, 0);
cmd->h = (unsigned short)NK_MAX(r.h, 0);
cmd->color = c;
}
NK_API void
nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
float a_min, float a_max, float line_thickness, struct nk_color c)
{
struct nk_command_arc *cmd;
if (!b || c.a == 0 || line_thickness <= 0) return;
cmd = (struct nk_command_arc*)
nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));
if (!cmd) return;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->cx = (short)cx;
cmd->cy = (short)cy;
cmd->r = (unsigned short)radius;
cmd->a[0] = a_min;
cmd->a[1] = a_max;
cmd->color = c;
}
NK_API void
nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
float a_min, float a_max, struct nk_color c)
{
struct nk_command_arc_filled *cmd;
NK_ASSERT(b);
if (!b || c.a == 0) return;
cmd = (struct nk_command_arc_filled*)
nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));
if (!cmd) return;
cmd->cx = (short)cx;
cmd->cy = (short)cy;
cmd->r = (unsigned short)radius;
cmd->a[0] = a_min;
cmd->a[1] = a_max;
cmd->color = c;
}
NK_API void
nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
float y1, float x2, float y2, float line_thickness, struct nk_color c)
{
struct nk_command_triangle *cmd;
NK_ASSERT(b);
if (!b || c.a == 0 || line_thickness <= 0) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
!NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
!NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
return;
}
cmd = (struct nk_command_triangle*)
nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));
if (!cmd) return;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->a.x = (short)x0;
cmd->a.y = (short)y0;
cmd->b.x = (short)x1;
cmd->b.y = (short)y1;
cmd->c.x = (short)x2;
cmd->c.y = (short)y2;
cmd->color = c;
}
NK_API void
nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
float y1, float x2, float y2, struct nk_color c)
{
struct nk_command_triangle_filled *cmd;
NK_ASSERT(b);
if (!b || c.a == 0) return;
if (!b) return;
if (b->use_clipping) {
const struct nk_rect *clip = &b->clip;
if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
!NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
!NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
return;
}
cmd = (struct nk_command_triangle_filled*)
nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));
if (!cmd) return;
cmd->a.x = (short)x0;
cmd->a.y = (short)y0;
cmd->b.x = (short)x1;
cmd->b.y = (short)y1;
cmd->c.x = (short)x2;
cmd->c.y = (short)y2;
cmd->color = c;
}
NK_API void
nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count,
float line_thickness, struct nk_color col)
{
int i;
nk_size size = 0;
struct nk_command_polygon *cmd;
NK_ASSERT(b);
if (!b || col.a == 0 || line_thickness <= 0) return;
size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);
if (!cmd) return;
cmd->color = col;
cmd->line_thickness = (unsigned short)line_thickness;
cmd->point_count = (unsigned short)point_count;
for (i = 0; i < point_count; ++i) {
cmd->points[i].x = (short)points[i*2];
cmd->points[i].y = (short)points[i*2+1];
}
}
NK_API void
nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
struct nk_color col)
{
int i;
nk_size size = 0;
struct nk_command_polygon_filled *cmd;
NK_ASSERT(b);
if (!b || col.a == 0) return;
size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
cmd = (struct nk_command_polygon_filled*)
nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);
if (!cmd) return;
cmd->color = col;
cmd->point_count = (unsigned short)point_count;
for (i = 0; i < point_count; ++i) {
cmd->points[i].x = (short)points[i*2+0];
cmd->points[i].y = (short)points[i*2+1];
}
}
NK_API void
nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count,
float line_thickness, struct nk_color col)
{
int i;
nk_size size = 0;
struct nk_command_polyline *cmd;
NK_ASSERT(b);
if (!b || col.a == 0 || line_thickness <= 0) return;
size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);
if (!cmd) return;
cmd->color = col;
cmd->point_count = (unsigned short)point_count;
cmd->line_thickness = (unsigned short)line_thickness;
for (i = 0; i < point_count; ++i) {
cmd->points[i].x = (short)points[i*2];
cmd->points[i].y = (short)points[i*2+1];
}
}
NK_API void
nk_draw_image(struct nk_command_buffer *b, struct nk_rect r,
const struct nk_image *img, struct nk_color col)
{
struct nk_command_image *cmd;
NK_ASSERT(b);
if (!b) return;
if (b->use_clipping) {
const struct nk_rect *c = &b->clip;
if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
return;
}
cmd = (struct nk_command_image*)
nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));
if (!cmd) return;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)NK_MAX(0, r.w);
cmd->h = (unsigned short)NK_MAX(0, r.h);
cmd->img = *img;
cmd->col = col;
}
NK_API void
nk_push_custom(struct nk_command_buffer *b, struct nk_rect r,
nk_command_custom_callback cb, nk_handle usr)
{
struct nk_command_custom *cmd;
NK_ASSERT(b);
if (!b) return;
if (b->use_clipping) {
const struct nk_rect *c = &b->clip;
if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
return;
}
cmd = (struct nk_command_custom*)
nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));
if (!cmd) return;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)NK_MAX(0, r.w);
cmd->h = (unsigned short)NK_MAX(0, r.h);
cmd->callback_data = usr;
cmd->callback = cb;
}
NK_API void
nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
const char *string, int length, const struct nk_user_font *font,
struct nk_color bg, struct nk_color fg)
{
float text_width = 0;
struct nk_command_text *cmd;
NK_ASSERT(b);
NK_ASSERT(font);
if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;
if (b->use_clipping) {
const struct nk_rect *c = &b->clip;
if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
return;
}
/* make sure text fits inside bounds */
text_width = font->width(font->userdata, font->height, string, length);
if (text_width > r.w){
int glyphs = 0;
float txt_width = (float)text_width;
length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);
}
if (!length) return;
cmd = (struct nk_command_text*)
nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));
if (!cmd) return;
cmd->x = (short)r.x;
cmd->y = (short)r.y;
cmd->w = (unsigned short)r.w;
cmd->h = (unsigned short)r.h;
cmd->background = bg;
cmd->foreground = fg;
cmd->font = font;
cmd->length = length;
cmd->height = font->height;
NK_MEMCPY(cmd->string, string, (nk_size)length);
cmd->string[length] = '\0';
}

806
src/nuklear_edit.c Normal file
View File

@ -0,0 +1,806 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* FILTER
*
* ===============================================================*/
NK_API int
nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(unicode);
NK_UNUSED(box);
return nk_true;
}
NK_API int
nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if (unicode > 128) return nk_false;
else return nk_true;
}
NK_API int
nk_filter_float(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
return nk_false;
else return nk_true;
}
NK_API int
nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if ((unicode < '0' || unicode > '9') && unicode != '-')
return nk_false;
else return nk_true;
}
NK_API int
nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if ((unicode < '0' || unicode > '9') &&
(unicode < 'a' || unicode > 'f') &&
(unicode < 'A' || unicode > 'F'))
return nk_false;
else return nk_true;
}
NK_API int
nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if (unicode < '0' || unicode > '7')
return nk_false;
else return nk_true;
}
NK_API int
nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(box);
if (unicode != '0' && unicode != '1')
return nk_false;
else return nk_true;
}
/* ===============================================================
*
* EDIT
*
* ===============================================================*/
NK_LIB void
nk_edit_draw_text(struct nk_command_buffer *out,
const struct nk_style_edit *style, float pos_x, float pos_y,
float x_offset, const char *text, int byte_len, float row_height,
const struct nk_user_font *font, struct nk_color background,
struct nk_color foreground, int is_selected)
{
NK_ASSERT(out);
NK_ASSERT(font);
NK_ASSERT(style);
if (!text || !byte_len || !out || !style) return;
{int glyph_len = 0;
nk_rune unicode = 0;
int text_len = 0;
float line_width = 0;
float glyph_width;
const char *line = text;
float line_offset = 0;
int line_count = 0;
struct nk_text txt;
txt.padding = nk_vec2(0,0);
txt.background = background;
txt.text = foreground;
glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
if (!glyph_len) return;
while ((text_len < byte_len) && glyph_len)
{
if (unicode == '\n') {
/* new line separator so draw previous line */
struct nk_rect label;
label.y = pos_y + line_offset;
label.h = row_height;
label.w = line_width;
label.x = pos_x;
if (!line_count)
label.x += x_offset;
if (is_selected) /* selection needs to draw different background color */
nk_fill_rect(out, label, 0, background);
nk_widget_text(out, label, line, (int)((text + text_len) - line),
&txt, NK_TEXT_CENTERED, font);
text_len++;
line_count++;
line_width = 0;
line = text + text_len;
line_offset += row_height;
glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));
continue;
}
if (unicode == '\r') {
text_len++;
glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
continue;
}
glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
line_width += (float)glyph_width;
text_len += glyph_len;
glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
continue;
}
if (line_width > 0) {
/* draw last line */
struct nk_rect label;
label.y = pos_y + line_offset;
label.h = row_height;
label.w = line_width;
label.x = pos_x;
if (!line_count)
label.x += x_offset;
if (is_selected)
nk_fill_rect(out, label, 0, background);
nk_widget_text(out, label, line, (int)((text + text_len) - line),
&txt, NK_TEXT_LEFT, font);
}}
}
NK_LIB nk_flags
nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,
struct nk_text_edit *edit, const struct nk_style_edit *style,
struct nk_input *in, const struct nk_user_font *font)
{
struct nk_rect area;
nk_flags ret = 0;
float row_height;
char prev_state = 0;
char is_hovered = 0;
char select_all = 0;
char cursor_follow = 0;
struct nk_rect old_clip;
struct nk_rect clip;
NK_ASSERT(state);
NK_ASSERT(out);
NK_ASSERT(style);
if (!state || !out || !style)
return ret;
/* visible text area calculation */
area.x = bounds.x + style->padding.x + style->border;
area.y = bounds.y + style->padding.y + style->border;
area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);
area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);
if (flags & NK_EDIT_MULTILINE)
area.w = NK_MAX(0, area.w - style->scrollbar_size.x);
row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;
/* calculate clipping rectangle */
old_clip = out->clip;
nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
/* update edit state */
prev_state = (char)edit->active;
is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds);
if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {
edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,
bounds.x, bounds.y, bounds.w, bounds.h);
}
/* (de)activate text editor */
if (!prev_state && edit->active) {
const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?
NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;
nk_textedit_clear_state(edit, type, filter);
if (flags & NK_EDIT_AUTO_SELECT)
select_all = nk_true;
if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {
edit->cursor = edit->string.len;
in = 0;
}
} else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;
if (flags & NK_EDIT_READ_ONLY)
edit->mode = NK_TEXT_EDIT_MODE_VIEW;
else if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
edit->mode = NK_TEXT_EDIT_MODE_INSERT;
ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;
if (prev_state != edit->active)
ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;
/* handle user input */
if (edit->active && in)
{
int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;
const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;
const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;
/* mouse click handler */
is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);
if (select_all) {
nk_textedit_select_all(edit);
} else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
in->mouse.buttons[NK_BUTTON_LEFT].clicked) {
nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);
} else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
(in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) {
nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);
cursor_follow = nk_true;
} else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&
in->mouse.buttons[NK_BUTTON_RIGHT].down) {
nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);
nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);
cursor_follow = nk_true;
}
{int i; /* keyboard input */
int old_mode = edit->mode;
for (i = 0; i < NK_KEY_MAX; ++i) {
if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */
if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {
nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);
cursor_follow = nk_true;
}
}
if (old_mode != edit->mode) {
in->keyboard.text_len = 0;
}}
/* text input */
edit->filter = filter;
if (in->keyboard.text_len) {
nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);
cursor_follow = nk_true;
in->keyboard.text_len = 0;
}
/* enter key handler */
if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {
cursor_follow = nk_true;
if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)
nk_textedit_text(edit, "\n", 1);
else if (flags & NK_EDIT_SIG_ENTER)
ret |= NK_EDIT_COMMITED;
else nk_textedit_text(edit, "\n", 1);
}
/* cut & copy handler */
{int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);
int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);
if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))
{
int glyph_len;
nk_rune unicode;
const char *text;
int b = edit->select_start;
int e = edit->select_end;
int begin = NK_MIN(b, e);
int end = NK_MAX(b, e);
text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);
if (edit->clip.copy)
edit->clip.copy(edit->clip.userdata, text, end - begin);
if (cut && !(flags & NK_EDIT_READ_ONLY)){
nk_textedit_cut(edit);
cursor_follow = nk_true;
}
}}
/* paste handler */
{int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);
if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {
edit->clip.paste(edit->clip.userdata, edit);
cursor_follow = nk_true;
}}
/* tab handler */
{int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);
if (tab && (flags & NK_EDIT_ALLOW_TAB)) {
nk_textedit_text(edit, " ", 4);
cursor_follow = nk_true;
}}
}
/* set widget state */
if (edit->active)
*state = NK_WIDGET_STATE_ACTIVE;
else nk_widget_state_reset(state);
if (is_hovered)
*state |= NK_WIDGET_STATE_HOVERED;
/* DRAW EDIT */
{const char *text = nk_str_get_const(&edit->string);
int len = nk_str_len_char(&edit->string);
{/* select background colors/images */
const struct nk_style_item *background;
if (*state & NK_WIDGET_STATE_ACTIVED)
background = &style->active;
else if (*state & NK_WIDGET_STATE_HOVER)
background = &style->hover;
else background = &style->normal;
/* draw background frame */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color);
nk_fill_rect(out, bounds, style->rounding, background->data.color);
} else nk_draw_image(out, bounds, &background->data.image, nk_white);}
area.w = NK_MAX(0, area.w - style->cursor_size);
if (edit->active)
{
int total_lines = 1;
struct nk_vec2 text_size = nk_vec2(0,0);
/* text pointer positions */
const char *cursor_ptr = 0;
const char *select_begin_ptr = 0;
const char *select_end_ptr = 0;
/* 2D pixel positions */
struct nk_vec2 cursor_pos = nk_vec2(0,0);
struct nk_vec2 selection_offset_start = nk_vec2(0,0);
struct nk_vec2 selection_offset_end = nk_vec2(0,0);
int selection_begin = NK_MIN(edit->select_start, edit->select_end);
int selection_end = NK_MAX(edit->select_start, edit->select_end);
/* calculate total line count + total space + cursor/selection position */
float line_width = 0.0f;
if (text && len)
{
/* utf8 encoding */
float glyph_width;
int glyph_len = 0;
nk_rune unicode = 0;
int text_len = 0;
int glyphs = 0;
int row_begin = 0;
glyph_len = nk_utf_decode(text, &unicode, len);
glyph_width = font->width(font->userdata, font->height, text, glyph_len);
line_width = 0;
/* iterate all lines */
while ((text_len < len) && glyph_len)
{
/* set cursor 2D position and line */
if (!cursor_ptr && glyphs == edit->cursor)
{
int glyph_offset;
struct nk_vec2 out_offset;
struct nk_vec2 row_size;
const char *remaining;
/* calculate 2d position */
cursor_pos.y = (float)(total_lines-1) * row_height;
row_size = nk_text_calculate_text_bounds(font, text+row_begin,
text_len-row_begin, row_height, &remaining,
&out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
cursor_pos.x = row_size.x;
cursor_ptr = text + text_len;
}
/* set start selection 2D position and line */
if (!select_begin_ptr && edit->select_start != edit->select_end &&
glyphs == selection_begin)
{
int glyph_offset;
struct nk_vec2 out_offset;
struct nk_vec2 row_size;
const char *remaining;
/* calculate 2d position */
selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;
row_size = nk_text_calculate_text_bounds(font, text+row_begin,
text_len-row_begin, row_height, &remaining,
&out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
selection_offset_start.x = row_size.x;
select_begin_ptr = text + text_len;
}
/* set end selection 2D position and line */
if (!select_end_ptr && edit->select_start != edit->select_end &&
glyphs == selection_end)
{
int glyph_offset;
struct nk_vec2 out_offset;
struct nk_vec2 row_size;
const char *remaining;
/* calculate 2d position */
selection_offset_end.y = (float)(total_lines-1) * row_height;
row_size = nk_text_calculate_text_bounds(font, text+row_begin,
text_len-row_begin, row_height, &remaining,
&out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
selection_offset_end.x = row_size.x;
select_end_ptr = text + text_len;
}
if (unicode == '\n') {
text_size.x = NK_MAX(text_size.x, line_width);
total_lines++;
line_width = 0;
text_len++;
glyphs++;
row_begin = text_len;
glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
continue;
}
glyphs++;
text_len += glyph_len;
line_width += (float)glyph_width;
glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
glyph_width = font->width(font->userdata, font->height,
text+text_len, glyph_len);
continue;
}
text_size.y = (float)total_lines * row_height;
/* handle case when cursor is at end of text buffer */
if (!cursor_ptr && edit->cursor == edit->string.len) {
cursor_pos.x = line_width;
cursor_pos.y = text_size.y - row_height;
}
}
{
/* scrollbar */
if (cursor_follow)
{
/* update scrollbar to follow cursor */
if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {
/* horizontal scroll */
const float scroll_increment = area.w * 0.25f;
if (cursor_pos.x < edit->scrollbar.x)
edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);
if (cursor_pos.x >= edit->scrollbar.x + area.w)
edit->scrollbar.x = (float)(int)NK_MAX(0.0f, edit->scrollbar.x + scroll_increment);
} else edit->scrollbar.x = 0;
if (flags & NK_EDIT_MULTILINE) {
/* vertical scroll */
if (cursor_pos.y < edit->scrollbar.y)
edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height);
if (cursor_pos.y >= edit->scrollbar.y + area.h)
edit->scrollbar.y = edit->scrollbar.y + row_height;
} else edit->scrollbar.y = 0;
}
/* scrollbar widget */
if (flags & NK_EDIT_MULTILINE)
{
nk_flags ws;
struct nk_rect scroll;
float scroll_target;
float scroll_offset;
float scroll_step;
float scroll_inc;
scroll = area;
scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;
scroll.w = style->scrollbar_size.x;
scroll_offset = edit->scrollbar.y;
scroll_step = scroll.h * 0.10f;
scroll_inc = scroll.h * 0.01f;
scroll_target = text_size.y;
edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0,
scroll_offset, scroll_target, scroll_step, scroll_inc,
&style->scrollbar, in, font);
}
}
/* draw text */
{struct nk_color background_color;
struct nk_color text_color;
struct nk_color sel_background_color;
struct nk_color sel_text_color;
struct nk_color cursor_color;
struct nk_color cursor_text_color;
const struct nk_style_item *background;
nk_push_scissor(out, clip);
/* select correct colors to draw */
if (*state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
text_color = style->text_active;
sel_text_color = style->selected_text_hover;
sel_background_color = style->selected_hover;
cursor_color = style->cursor_hover;
cursor_text_color = style->cursor_text_hover;
} else if (*state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
text_color = style->text_hover;
sel_text_color = style->selected_text_hover;
sel_background_color = style->selected_hover;
cursor_text_color = style->cursor_text_hover;
cursor_color = style->cursor_hover;
} else {
background = &style->normal;
text_color = style->text_normal;
sel_text_color = style->selected_text_normal;
sel_background_color = style->selected_normal;
cursor_color = style->cursor_normal;
cursor_text_color = style->cursor_text_normal;
}
if (background->type == NK_STYLE_ITEM_IMAGE)
background_color = nk_rgba(0,0,0,0);
else background_color = background->data.color;
if (edit->select_start == edit->select_end) {
/* no selection so just draw the complete text */
const char *begin = nk_str_get_const(&edit->string);
int l = nk_str_len_char(&edit->string);
nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
background_color, text_color, nk_false);
} else {
/* edit has selection so draw 1-3 text chunks */
if (edit->select_start != edit->select_end && selection_begin > 0){
/* draw unselected text before selection */
const char *begin = nk_str_get_const(&edit->string);
NK_ASSERT(select_begin_ptr);
nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),
row_height, font, background_color, text_color, nk_false);
}
if (edit->select_start != edit->select_end) {
/* draw selected text */
NK_ASSERT(select_begin_ptr);
if (!select_end_ptr) {
const char *begin = nk_str_get_const(&edit->string);
select_end_ptr = begin + nk_str_len_char(&edit->string);
}
nk_edit_draw_text(out, style,
area.x - edit->scrollbar.x,
area.y + selection_offset_start.y - edit->scrollbar.y,
selection_offset_start.x,
select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),
row_height, font, sel_background_color, sel_text_color, nk_true);
}
if ((edit->select_start != edit->select_end &&
selection_end < edit->string.len))
{
/* draw unselected text after selected text */
const char *begin = select_end_ptr;
const char *end = nk_str_get_const(&edit->string) +
nk_str_len_char(&edit->string);
NK_ASSERT(select_end_ptr);
nk_edit_draw_text(out, style,
area.x - edit->scrollbar.x,
area.y + selection_offset_end.y - edit->scrollbar.y,
selection_offset_end.x,
begin, (int)(end - begin), row_height, font,
background_color, text_color, nk_true);
}
}
/* cursor */
if (edit->select_start == edit->select_end)
{
if (edit->cursor >= nk_str_len(&edit->string) ||
(cursor_ptr && *cursor_ptr == '\n')) {
/* draw cursor at end of line */
struct nk_rect cursor;
cursor.w = style->cursor_size;
cursor.h = font->height;
cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;
cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;
cursor.y -= edit->scrollbar.y;
nk_fill_rect(out, cursor, 0, cursor_color);
} else {
/* draw cursor inside text */
int glyph_len;
struct nk_rect label;
struct nk_text txt;
nk_rune unicode;
NK_ASSERT(cursor_ptr);
glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);
label.x = area.x + cursor_pos.x - edit->scrollbar.x;
label.y = area.y + cursor_pos.y - edit->scrollbar.y;
label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);
label.h = row_height;
txt.padding = nk_vec2(0,0);
txt.background = cursor_color;;
txt.text = cursor_text_color;
nk_fill_rect(out, label, 0, cursor_color);
nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);
}
}}
} else {
/* not active so just draw text */
int l = nk_str_len_char(&edit->string);
const char *begin = nk_str_get_const(&edit->string);
const struct nk_style_item *background;
struct nk_color background_color;
struct nk_color text_color;
nk_push_scissor(out, clip);
if (*state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
text_color = style->text_active;
} else if (*state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
text_color = style->text_hover;
} else {
background = &style->normal;
text_color = style->text_normal;
}
if (background->type == NK_STYLE_ITEM_IMAGE)
background_color = nk_rgba(0,0,0,0);
else background_color = background->data.color;
nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
background_color, text_color, nk_false);
}
nk_push_scissor(out, old_clip);}
return ret;
}
NK_API void
nk_edit_focus(struct nk_context *ctx, nk_flags flags)
{
nk_hash hash;
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return;
win = ctx->current;
hash = win->edit.seq;
win->edit.active = nk_true;
win->edit.name = hash;
if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;
}
NK_API void
nk_edit_unfocus(struct nk_context *ctx)
{
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return;
win = ctx->current;
win->edit.active = nk_false;
win->edit.name = 0;
}
NK_API nk_flags
nk_edit_string(struct nk_context *ctx, nk_flags flags,
char *memory, int *len, int max, nk_plugin_filter filter)
{
nk_hash hash;
nk_flags state;
struct nk_text_edit *edit;
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(memory);
NK_ASSERT(len);
if (!ctx || !memory || !len)
return 0;
filter = (!filter) ? nk_filter_default: filter;
win = ctx->current;
hash = win->edit.seq;
edit = &ctx->text_edit;
nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?
NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);
if (win->edit.active && hash == win->edit.name) {
if (flags & NK_EDIT_NO_CURSOR)
edit->cursor = nk_utf_len(memory, *len);
else edit->cursor = win->edit.cursor;
if (!(flags & NK_EDIT_SELECTABLE)) {
edit->select_start = win->edit.cursor;
edit->select_end = win->edit.cursor;
} else {
edit->select_start = win->edit.sel_start;
edit->select_end = win->edit.sel_end;
}
edit->mode = win->edit.mode;
edit->scrollbar.x = (float)win->edit.scrollbar.x;
edit->scrollbar.y = (float)win->edit.scrollbar.y;
edit->active = nk_true;
} else edit->active = nk_false;
max = NK_MAX(1, max);
*len = NK_MIN(*len, max-1);
nk_str_init_fixed(&edit->string, memory, (nk_size)max);
edit->string.buffer.allocated = (nk_size)*len;
edit->string.len = nk_utf_len(memory, *len);
state = nk_edit_buffer(ctx, flags, edit, filter);
*len = (int)edit->string.buffer.allocated;
if (edit->active) {
win->edit.cursor = edit->cursor;
win->edit.sel_start = edit->select_start;
win->edit.sel_end = edit->select_end;
win->edit.mode = edit->mode;
win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;
win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;
} return state;
}
NK_API nk_flags
nk_edit_buffer(struct nk_context *ctx, nk_flags flags,
struct nk_text_edit *edit, nk_plugin_filter filter)
{
struct nk_window *win;
struct nk_style *style;
struct nk_input *in;
enum nk_widget_layout_states state;
struct nk_rect bounds;
nk_flags ret_flags = 0;
unsigned char prev_state;
nk_hash hash;
/* make sure correct values */
NK_ASSERT(ctx);
NK_ASSERT(edit);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
style = &ctx->style;
state = nk_widget(&bounds, ctx);
if (!state) return state;
in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
/* check if edit is currently hot item */
hash = win->edit.seq++;
if (win->edit.active && hash == win->edit.name) {
if (flags & NK_EDIT_NO_CURSOR)
edit->cursor = edit->string.len;
if (!(flags & NK_EDIT_SELECTABLE)) {
edit->select_start = edit->cursor;
edit->select_end = edit->cursor;
}
if (flags & NK_EDIT_CLIPBOARD)
edit->clip = ctx->clip;
edit->active = (unsigned char)win->edit.active;
} else edit->active = nk_false;
edit->mode = win->edit.mode;
filter = (!filter) ? nk_filter_default: filter;
prev_state = (unsigned char)edit->active;
in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,
filter, edit, &style->edit, in, style->font);
if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
if (edit->active && prev_state != edit->active) {
/* current edit is now hot */
win->edit.active = nk_true;
win->edit.name = hash;
} else if (prev_state && !edit->active) {
/* current edit is now cold */
win->edit.active = nk_false;
} return ret_flags;
}
NK_API nk_flags
nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,
char *buffer, int max, nk_plugin_filter filter)
{
nk_flags result;
int len = nk_strlen(buffer);
result = nk_edit_string(ctx, flags, buffer, &len, max, filter);
buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0';
return result;
}

3380
src/nuklear_font.c Normal file

File diff suppressed because it is too large Load Diff

169
src/nuklear_group.c Normal file
View File

@ -0,0 +1,169 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* GROUP
*
* ===============================================================*/
NK_API int
nk_group_scrolled_offset_begin(struct nk_context *ctx,
nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)
{
struct nk_rect bounds;
struct nk_window panel;
struct nk_window *win;
win = ctx->current;
nk_panel_alloc_space(&bounds, ctx);
{const struct nk_rect *c = &win->layout->clip;
if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&
!(flags & NK_WINDOW_MOVABLE)) {
return 0;
}}
if (win->flags & NK_WINDOW_ROM)
flags |= NK_WINDOW_ROM;
/* initialize a fake window to create the panel from */
nk_zero(&panel, sizeof(panel));
panel.bounds = bounds;
panel.flags = flags;
panel.scrollbar.x = *x_offset;
panel.scrollbar.y = *y_offset;
panel.buffer = win->buffer;
panel.layout = (struct nk_panel*)nk_create_panel(ctx);
ctx->current = &panel;
nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);
win->buffer = panel.buffer;
win->buffer.clip = panel.layout->clip;
panel.layout->offset_x = x_offset;
panel.layout->offset_y = y_offset;
panel.layout->parent = win->layout;
win->layout = panel.layout;
ctx->current = win;
if ((panel.layout->flags & NK_WINDOW_CLOSED) ||
(panel.layout->flags & NK_WINDOW_MINIMIZED))
{
nk_flags f = panel.layout->flags;
nk_group_scrolled_end(ctx);
if (f & NK_WINDOW_CLOSED)
return NK_WINDOW_CLOSED;
if (f & NK_WINDOW_MINIMIZED)
return NK_WINDOW_MINIMIZED;
}
return 1;
}
NK_API void
nk_group_scrolled_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *parent;
struct nk_panel *g;
struct nk_rect clip;
struct nk_window pan;
struct nk_vec2 panel_padding;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return;
/* make sure nk_group_begin was called correctly */
NK_ASSERT(ctx->current);
win = ctx->current;
NK_ASSERT(win->layout);
g = win->layout;
NK_ASSERT(g->parent);
parent = g->parent;
/* dummy window */
nk_zero_struct(pan);
panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);
pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);
pan.bounds.x = g->bounds.x - panel_padding.x;
pan.bounds.w = g->bounds.w + 2 * panel_padding.x;
pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;
if (g->flags & NK_WINDOW_BORDER) {
pan.bounds.x -= g->border;
pan.bounds.y -= g->border;
pan.bounds.w += 2*g->border;
pan.bounds.h += 2*g->border;
}
if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {
pan.bounds.w += ctx->style.window.scrollbar_size.x;
pan.bounds.h += ctx->style.window.scrollbar_size.y;
}
pan.scrollbar.x = *g->offset_x;
pan.scrollbar.y = *g->offset_y;
pan.flags = g->flags;
pan.buffer = win->buffer;
pan.layout = g;
pan.parent = win;
ctx->current = &pan;
/* make sure group has correct clipping rectangle */
nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,
pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);
nk_push_scissor(&pan.buffer, clip);
nk_end(ctx);
win->buffer = pan.buffer;
nk_push_scissor(&win->buffer, parent->clip);
ctx->current = win;
win->layout = parent;
g->bounds = pan.bounds;
return;
}
NK_API int
nk_group_scrolled_begin(struct nk_context *ctx,
struct nk_scroll *scroll, const char *title, nk_flags flags)
{
return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);
}
NK_API int
nk_group_begin_titled(struct nk_context *ctx, const char *id,
const char *title, nk_flags flags)
{
int id_len;
nk_hash id_hash;
struct nk_window *win;
nk_uint *x_offset;
nk_uint *y_offset;
NK_ASSERT(ctx);
NK_ASSERT(id);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !id)
return 0;
/* find persistent group scrollbar value */
win = ctx->current;
id_len = (int)nk_strlen(id);
id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);
x_offset = nk_find_value(win, id_hash);
if (!x_offset) {
x_offset = nk_add_value(ctx, win, id_hash, 0);
y_offset = nk_add_value(ctx, win, id_hash+1, 0);
NK_ASSERT(x_offset);
NK_ASSERT(y_offset);
if (!x_offset || !y_offset) return 0;
*x_offset = *y_offset = 0;
} else y_offset = nk_find_value(win, id_hash+1);
return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
}
NK_API int
nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)
{
return nk_group_begin_titled(ctx, title, title, flags);
}
NK_API void
nk_group_end(struct nk_context *ctx)
{
nk_group_scrolled_end(ctx);
}

140
src/nuklear_image.c Normal file
View File

@ -0,0 +1,140 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* IMAGE
*
* ===============================================================*/
NK_API nk_handle
nk_handle_ptr(void *ptr)
{
nk_handle handle = {0};
handle.ptr = ptr;
return handle;
}
NK_API nk_handle
nk_handle_id(int id)
{
nk_handle handle;
nk_zero_struct(handle);
handle.id = id;
return handle;
}
NK_API struct nk_image
nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
s.handle.ptr = ptr;
s.w = w; s.h = h;
s.region[0] = (unsigned short)r.x;
s.region[1] = (unsigned short)r.y;
s.region[2] = (unsigned short)r.w;
s.region[3] = (unsigned short)r.h;
return s;
}
NK_API struct nk_image
nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
s.handle.id = id;
s.w = w; s.h = h;
s.region[0] = (unsigned short)r.x;
s.region[1] = (unsigned short)r.y;
s.region[2] = (unsigned short)r.w;
s.region[3] = (unsigned short)r.h;
return s;
}
NK_API struct nk_image
nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h,
struct nk_rect r)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
s.handle = handle;
s.w = w; s.h = h;
s.region[0] = (unsigned short)r.x;
s.region[1] = (unsigned short)r.y;
s.region[2] = (unsigned short)r.w;
s.region[3] = (unsigned short)r.h;
return s;
}
NK_API struct nk_image
nk_image_handle(nk_handle handle)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
s.handle = handle;
s.w = 0; s.h = 0;
s.region[0] = 0;
s.region[1] = 0;
s.region[2] = 0;
s.region[3] = 0;
return s;
}
NK_API struct nk_image
nk_image_ptr(void *ptr)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
NK_ASSERT(ptr);
s.handle.ptr = ptr;
s.w = 0; s.h = 0;
s.region[0] = 0;
s.region[1] = 0;
s.region[2] = 0;
s.region[3] = 0;
return s;
}
NK_API struct nk_image
nk_image_id(int id)
{
struct nk_image s;
nk_zero(&s, sizeof(s));
s.handle.id = id;
s.w = 0; s.h = 0;
s.region[0] = 0;
s.region[1] = 0;
s.region[2] = 0;
s.region[3] = 0;
return s;
}
NK_API int
nk_image_is_subimage(const struct nk_image* img)
{
NK_ASSERT(img);
return !(img->w == 0 && img->h == 0);
}
NK_API void
nk_image(struct nk_context *ctx, struct nk_image img)
{
struct nk_window *win;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return;
win = ctx->current;
if (!nk_widget(&bounds, ctx)) return;
nk_draw_image(&win->buffer, bounds, &img, nk_white);
}
NK_API void
nk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col)
{
struct nk_window *win;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return;
win = ctx->current;
if (!nk_widget(&bounds, ctx)) return;
nk_draw_image(&win->buffer, bounds, &img, col);
}

253
src/nuklear_input.c Normal file
View File

@ -0,0 +1,253 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* INPUT
*
* ===============================================================*/
NK_API void
nk_input_begin(struct nk_context *ctx)
{
int i;
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
for (i = 0; i < NK_BUTTON_MAX; ++i)
in->mouse.buttons[i].clicked = 0;
in->keyboard.text_len = 0;
in->mouse.scroll_delta = nk_vec2(0,0);
in->mouse.prev.x = in->mouse.pos.x;
in->mouse.prev.y = in->mouse.pos.y;
in->mouse.delta.x = 0;
in->mouse.delta.y = 0;
for (i = 0; i < NK_KEY_MAX; i++)
in->keyboard.keys[i].clicked = 0;
}
NK_API void
nk_input_end(struct nk_context *ctx)
{
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
if (in->mouse.grab)
in->mouse.grab = 0;
if (in->mouse.ungrab) {
in->mouse.grabbed = 0;
in->mouse.ungrab = 0;
in->mouse.grab = 0;
}
}
NK_API void
nk_input_motion(struct nk_context *ctx, int x, int y)
{
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
in->mouse.pos.x = (float)x;
in->mouse.pos.y = (float)y;
in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;
in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;
}
NK_API void
nk_input_key(struct nk_context *ctx, enum nk_keys key, int down)
{
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
if (in->keyboard.keys[key].down != down)
in->keyboard.keys[key].clicked++;
in->keyboard.keys[key].down = down;
}
NK_API void
nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down)
{
struct nk_mouse_button *btn;
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
if (in->mouse.buttons[id].down == down) return;
btn = &in->mouse.buttons[id];
btn->clicked_pos.x = (float)x;
btn->clicked_pos.y = (float)y;
btn->down = down;
btn->clicked++;
}
NK_API void
nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)
{
NK_ASSERT(ctx);
if (!ctx) return;
ctx->input.mouse.scroll_delta.x += val.x;
ctx->input.mouse.scroll_delta.y += val.y;
}
NK_API void
nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)
{
int len = 0;
nk_rune unicode;
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);
if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {
nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],
NK_INPUT_MAX - in->keyboard.text_len);
in->keyboard.text_len += len;
}
}
NK_API void
nk_input_char(struct nk_context *ctx, char c)
{
nk_glyph glyph;
NK_ASSERT(ctx);
if (!ctx) return;
glyph[0] = c;
nk_input_glyph(ctx, glyph);
}
NK_API void
nk_input_unicode(struct nk_context *ctx, nk_rune unicode)
{
nk_glyph rune;
NK_ASSERT(ctx);
if (!ctx) return;
nk_utf_encode(unicode, rune, NK_UTF_SIZE);
nk_input_glyph(ctx, rune);
}
NK_API int
nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)
{
const struct nk_mouse_button *btn;
if (!i) return nk_false;
btn = &i->mouse.buttons[id];
return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;
}
NK_API int
nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b)
{
const struct nk_mouse_button *btn;
if (!i) return nk_false;
btn = &i->mouse.buttons[id];
if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
return nk_false;
return nk_true;
}
NK_API int
nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b, int down)
{
const struct nk_mouse_button *btn;
if (!i) return nk_false;
btn = &i->mouse.buttons[id];
return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);
}
NK_API int
nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b)
{
const struct nk_mouse_button *btn;
if (!i) return nk_false;
btn = &i->mouse.buttons[id];
return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&
btn->clicked) ? nk_true : nk_false;
}
NK_API int
nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b, int down)
{
const struct nk_mouse_button *btn;
if (!i) return nk_false;
btn = &i->mouse.buttons[id];
return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&
btn->clicked) ? nk_true : nk_false;
}
NK_API int
nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)
{
int i, down = 0;
for (i = 0; i < NK_BUTTON_MAX; ++i)
down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);
return down;
}
NK_API int
nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)
{
if (!i) return nk_false;
return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);
}
NK_API int
nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)
{
if (!i) return nk_false;
return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);
}
NK_API int
nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)
{
if (!i) return nk_false;
if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;
return nk_input_is_mouse_click_in_rect(i, id, rect);
}
NK_API int
nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)
{
if (!i) return nk_false;
return i->mouse.buttons[id].down;
}
NK_API int
nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)
{
const struct nk_mouse_button *b;
if (!i) return nk_false;
b = &i->mouse.buttons[id];
if (b->down && b->clicked)
return nk_true;
return nk_false;
}
NK_API int
nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)
{
if (!i) return nk_false;
return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);
}
NK_API int
nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)
{
const struct nk_key *k;
if (!i) return nk_false;
k = &i->keyboard.keys[key];
if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))
return nk_true;
return nk_false;
}
NK_API int
nk_input_is_key_released(const struct nk_input *i, enum nk_keys key)
{
const struct nk_key *k;
if (!i) return nk_false;
k = &i->keyboard.keys[key];
if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))
return nk_true;
return nk_false;
}
NK_API int
nk_input_is_key_down(const struct nk_input *i, enum nk_keys key)
{
const struct nk_key *k;
if (!i) return nk_false;
k = &i->keyboard.keys[key];
if (k->down) return nk_true;
return nk_false;
}

335
src/nuklear_internal.h Normal file
View File

@ -0,0 +1,335 @@
#ifndef NK_INTERNAL_H
#define NK_INTERNAL_H
#ifndef NK_POOL_DEFAULT_CAPACITY
#define NK_POOL_DEFAULT_CAPACITY 16
#endif
#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE
#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)
#endif
#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE
#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)
#endif
/* standard library headers */
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
#include <stdlib.h> /* malloc, free */
#endif
#ifdef NK_INCLUDE_STANDARD_IO
#include <stdio.h> /* fopen, fclose,... */
#endif
#ifdef NK_INCLUDE_STANDARD_VARARGS
#include <stdarg.h> /* valist, va_start, va_end, ... */
#endif
#ifndef NK_ASSERT
#include <assert.h>
#define NK_ASSERT(expr) assert(expr)
#endif
#ifndef NK_MEMSET
#define NK_MEMSET nk_memset
#endif
#ifndef NK_MEMCPY
#define NK_MEMCPY nk_memcopy
#endif
#ifndef NK_SQRT
#define NK_SQRT nk_sqrt
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
#endif
#ifndef NK_COS
#define NK_COS nk_cos
#endif
#ifndef NK_STRTOD
#define NK_STRTOD nk_strtod
#endif
#ifndef NK_DTOA
#define NK_DTOA nk_dtoa
#endif
#define NK_DEFAULT (-1)
#ifndef NK_VSNPRINTF
/* If your compiler does support `vsnprintf` I would highly recommend
* defining this to vsnprintf instead since `vsprintf` is basically
* unbelievable unsafe and should *NEVER* be used. But I have to support
* it since C89 only provides this unsafe version. */
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\
(defined(__cplusplus) && (__cplusplus >= 201103L)) || \
(defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\
(defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\
defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)
#define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)
#else
#define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)
#endif
#endif
#define NK_SCHAR_MIN (-127)
#define NK_SCHAR_MAX 127
#define NK_UCHAR_MIN 0
#define NK_UCHAR_MAX 256
#define NK_SSHORT_MIN (-32767)
#define NK_SSHORT_MAX 32767
#define NK_USHORT_MIN 0
#define NK_USHORT_MAX 65535
#define NK_SINT_MIN (-2147483647)
#define NK_SINT_MAX 2147483647
#define NK_UINT_MIN 0
#define NK_UINT_MAX 4294967295u
/* Make sure correct type size:
* This will fire with a negative subscript error if the type sizes
* are set incorrectly by the compiler, and compile out if not */
NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));
NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
NK_STATIC_ASSERT(sizeof(nk_short) == 2);
NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
NK_STATIC_ASSERT(sizeof(nk_int) == 4);
NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};
#define NK_FLOAT_PRECISION 0.00000000000001
NK_GLOBAL const struct nk_color nk_red = {255,0,0,255};
NK_GLOBAL const struct nk_color nk_green = {0,255,0,255};
NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};
NK_GLOBAL const struct nk_color nk_white = {255,255,255,255};
NK_GLOBAL const struct nk_color nk_black = {0,0,0,255};
NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};
/* widget */
#define nk_widget_state_reset(s)\
if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\
(*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\
else (*(s)) = NK_WIDGET_STATE_INACTIVE;
/* math */
NK_LIB float nk_inv_sqrt(float n);
NK_LIB float nk_sqrt(float x);
NK_LIB float nk_sin(float x);
NK_LIB float nk_cos(float x);
NK_LIB nk_uint nk_round_up_pow2(nk_uint v);
NK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount);
NK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad);
NK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1);
NK_LIB double nk_pow(double x, int n);
NK_LIB int nk_ifloord(double x);
NK_LIB int nk_ifloorf(float x);
NK_LIB int nk_iceilf(float x);
NK_LIB int nk_log10(double n);
/* util */
enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};
NK_LIB int nk_is_lower(int c);
NK_LIB int nk_is_upper(int c);
NK_LIB int nk_to_upper(int c);
NK_LIB int nk_to_lower(int c);
NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);
NK_LIB void nk_memset(void *ptr, int c0, nk_size size);
NK_LIB void nk_zero(void *ptr, nk_size size);
NK_LIB char *nk_itoa(char *s, long n);
NK_LIB int nk_string_float_limit(char *string, int prec);
NK_LIB char *nk_dtoa(char *s, double n);
NK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);
NK_LIB struct nk_vec2 nk_text_calculate_text_bounds(const struct nk_user_font *font, const char *begin, int byte_len, float row_height, const char **remaining, struct nk_vec2 *out_offset, int *glyphs, int op);
#ifdef NK_INCLUDE_STANDARD_VARARGS
NK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args);
#endif
#ifdef NK_INCLUDE_STANDARD_IO
NK_LIB char *nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc);
#endif
/* buffer */
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size);
NK_LIB void nk_mfree(nk_handle unused, void *ptr);
#endif
NK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type);
NK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align);
NK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size);
/* draw */
NK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip);
NK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b);
NK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size);
NK_LIB void nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, struct nk_rect content, struct nk_color background, struct nk_color foreground, float border_width, const struct nk_user_font *font);
/* buffering */
NK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
NK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*);
NK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
NK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w);
NK_LIB void nk_build(struct nk_context *ctx);
/* text editor */
NK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter);
NK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
NK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
NK_LIB void nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, const struct nk_user_font *font, float row_height);
/* window */
enum nk_window_insert_location {
NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */
NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */
};
NK_LIB void *nk_create_window(struct nk_context *ctx);
NK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);
NK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);
NK_LIB struct nk_window *nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name);
NK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);
/* pool */
NK_LIB void nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, unsigned int capacity);
NK_LIB void nk_pool_free(struct nk_pool *pool);
NK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size);
NK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool);
/* page-element */
NK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx);
NK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem);
NK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem);
/* table */
NK_LIB struct nk_table* nk_create_table(struct nk_context *ctx);
NK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
NK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
NK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);
NK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);
NK_LIB nk_uint *nk_find_value(struct nk_window *win, nk_hash name);
/* panel */
NK_LIB void *nk_create_panel(struct nk_context *ctx);
NK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan);
NK_LIB int nk_panel_has_header(nk_flags flags, const char *title);
NK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type);
NK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type);
NK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type);
NK_LIB int nk_panel_is_sub(enum nk_panel_type type);
NK_LIB int nk_panel_is_nonblock(enum nk_panel_type type);
NK_LIB int nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type);
NK_LIB void nk_panel_end(struct nk_context *ctx);
/* layout */
NK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns);
NK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols);
NK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width);
NK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);
NK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);
NK_LIB void nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx);
/* popup */
NK_LIB int nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);
/* text */
struct nk_text {
struct nk_vec2 padding;
struct nk_color background;
struct nk_color text;
};
NK_LIB void nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, nk_flags a, const struct nk_user_font *f);
NK_LIB void nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, const struct nk_user_font *f);
/* button */
NK_LIB int nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior);
NK_LIB const struct nk_style_item* nk_draw_button(struct nk_command_buffer *out, const struct nk_rect *bounds, nk_flags state, const struct nk_style_button *style);
NK_LIB int nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, const struct nk_style_button *style, const struct nk_input *in, enum nk_button_behavior behavior, struct nk_rect *content);
NK_LIB void nk_draw_button_text(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const char *txt, int len, nk_flags text_alignment, const struct nk_user_font *font);
NK_LIB int nk_do_button_text(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *string, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);
NK_LIB void nk_draw_button_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, enum nk_symbol_type type, const struct nk_user_font *font);
NK_LIB int nk_do_button_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);
NK_LIB void nk_draw_button_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const struct nk_image *img);
NK_LIB int nk_do_button_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, enum nk_button_behavior b, const struct nk_style_button *style, const struct nk_input *in);
NK_LIB void nk_draw_button_text_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, const char *str, int len, enum nk_symbol_type type, const struct nk_user_font *font);
NK_LIB int nk_do_button_text_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, const char *str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);
NK_LIB void nk_draw_button_text_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, const char *str, int len, const struct nk_user_font *font, const struct nk_image *img);
NK_LIB int nk_do_button_text_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, const char* str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);
/* toggle */
enum nk_toggle_type {
NK_TOGGLE_CHECK,
NK_TOGGLE_OPTION
};
NK_LIB int nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, int active);
NK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, int active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font);
NK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, int active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font);
NK_LIB int nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, int *active, const char *str, int len, enum nk_toggle_type type, const struct nk_style_toggle *style, const struct nk_input *in, const struct nk_user_font *font);
/* progress */
NK_LIB nk_size nk_progress_behavior(nk_flags *state, struct nk_input *in, struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, int modifiable);
NK_LIB void nk_draw_progress(struct nk_command_buffer *out, nk_flags state, const struct nk_style_progress *style, const struct nk_rect *bounds, const struct nk_rect *scursor, nk_size value, nk_size max);
NK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, int modifiable, const struct nk_style_progress *style, struct nk_input *in);
/* slider */
NK_LIB float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps);
NK_LIB void nk_draw_slider(struct nk_command_buffer *out, nk_flags state, const struct nk_style_slider *style, const struct nk_rect *bounds, const struct nk_rect *visual_cursor, float min, float value, float max);
NK_LIB float nk_do_slider(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, float min, float val, float max, float step, const struct nk_style_slider *style, struct nk_input *in, const struct nk_user_font *font);
/* scrollbar */
NK_LIB float nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, int has_scrolling, const struct nk_rect *scroll, const struct nk_rect *cursor, const struct nk_rect *empty0, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o);
NK_LIB void nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, const struct nk_style_scrollbar *style, const struct nk_rect *bounds, const struct nk_rect *scroll);
NK_LIB float nk_do_scrollbarv(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);
NK_LIB float nk_do_scrollbarh(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);
/* selectable */
NK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, int active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, const char *string, int len, nk_flags align, const struct nk_user_font *font);
NK_LIB int nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
NK_LIB int nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
/* edit */
NK_LIB void nk_edit_draw_text(struct nk_command_buffer *out, const struct nk_style_edit *style, float pos_x, float pos_y, float x_offset, const char *text, int byte_len, float row_height, const struct nk_user_font *font, struct nk_color background, struct nk_color foreground, int is_selected);
NK_LIB nk_flags nk_do_edit(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, struct nk_text_edit *edit, const struct nk_style_edit *style, struct nk_input *in, const struct nk_user_font *font);
/* color-picker */
NK_LIB int nk_color_picker_behavior(nk_flags *state, const struct nk_rect *bounds, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf *color, const struct nk_input *in);
NK_LIB void nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf col);
NK_LIB int nk_do_color_picker(nk_flags *state, struct nk_command_buffer *out, struct nk_colorf *col, enum nk_color_format fmt, struct nk_rect bounds, struct nk_vec2 padding, const struct nk_input *in, const struct nk_user_font *font);
/* property */
enum nk_property_status {
NK_PROPERTY_DEFAULT,
NK_PROPERTY_EDIT,
NK_PROPERTY_DRAG
};
enum nk_property_filter {
NK_FILTER_INT,
NK_FILTER_FLOAT
};
enum nk_property_kind {
NK_PROPERTY_INT,
NK_PROPERTY_FLOAT,
NK_PROPERTY_DOUBLE
};
union nk_property {
int i;
float f;
double d;
};
struct nk_property_variant {
enum nk_property_kind kind;
union nk_property value;
union nk_property min_value;
union nk_property max_value;
union nk_property step;
};
NK_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step);
NK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step);
NK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step);
NK_LIB void nk_drag_behavior(nk_flags *state, const struct nk_input *in, struct nk_rect drag, struct nk_property_variant *variant, float inc_per_pixel);
NK_LIB void nk_property_behavior(nk_flags *ws, const struct nk_input *in, struct nk_rect property, struct nk_rect label, struct nk_rect edit, struct nk_rect empty, int *state, struct nk_property_variant *variant, float inc_per_pixel);
NK_LIB void nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, const char *name, int len, const struct nk_user_font *font);
NK_LIB void nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, int *state, int *cursor, int *select_begin, int *select_end, const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, const struct nk_user_font *font, struct nk_text_edit *text_edit, enum nk_button_behavior behavior);
NK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, float inc_per_pixel, const enum nk_property_filter filter);
#endif

758
src/nuklear_layout.c Normal file
View File

@ -0,0 +1,758 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* LAYOUT
*
* ===============================================================*/
NK_API void
nk_layout_set_min_row_height(struct nk_context *ctx, float height)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
layout->row.min_height = height;
}
NK_API void
nk_layout_reset_min_row_height(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
layout->row.min_height = ctx->style.font->height;
layout->row.min_height += ctx->style.text.padding.y*2;
layout->row.min_height += ctx->style.window.min_row_height_padding*2;
}
NK_LIB float
nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
float total_space, int columns)
{
float panel_padding;
float panel_spacing;
float panel_space;
struct nk_vec2 spacing;
struct nk_vec2 padding;
spacing = style->window.spacing;
padding = nk_panel_get_padding(style, type);
/* calculate the usable panel space */
panel_padding = 2 * padding.x;
panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
panel_space = total_space - panel_padding - panel_spacing;
return panel_space;
}
NK_LIB void
nk_panel_layout(const struct nk_context *ctx, struct nk_window *win,
float height, int cols)
{
struct nk_panel *layout;
const struct nk_style *style;
struct nk_command_buffer *out;
struct nk_vec2 item_spacing;
struct nk_color color;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
/* prefetch some configuration data */
layout = win->layout;
style = &ctx->style;
out = &win->buffer;
color = style->window.background;
item_spacing = style->window.spacing;
/* if one of these triggers you forgot to add an `if` condition around either
a window, group, popup, combobox or contextual menu `begin` and `end` block.
Example:
if (nk_begin(...) {...} nk_end(...); or
if (nk_group_begin(...) { nk_group_end(...);} */
NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
/* update the current row and set the current row layout */
layout->row.index = 0;
layout->at_y += layout->row.height;
layout->row.columns = cols;
if (height == 0.0f)
layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;
else layout->row.height = height + item_spacing.y;
layout->row.item_offset = 0;
if (layout->flags & NK_WINDOW_DYNAMIC) {
/* draw background for dynamic panels */
struct nk_rect background;
background.x = win->bounds.x;
background.w = win->bounds.w;
background.y = layout->at_y - 1.0f;
background.h = layout->row.height + 1.0f;
nk_fill_rect(out, background, 0, color);
}
}
NK_LIB void
nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
float height, int cols, int width)
{
/* update the current row and set the current row layout */
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
nk_panel_layout(ctx, win, height, cols);
if (fmt == NK_DYNAMIC)
win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;
else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;
win->layout->row.ratio = 0;
win->layout->row.filled = 0;
win->layout->row.item_offset = 0;
win->layout->row.item_width = (float)width;
}
NK_API float
nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width)
{
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(pixel_width);
if (!ctx || !ctx->current || !ctx->current->layout) return 0;
win = ctx->current;
return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);
}
NK_API void
nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
{
nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);
}
NK_API void
nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
{
nk_row_layout(ctx, NK_STATIC, height, cols, item_width);
}
NK_API void
nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,
float row_height, int cols)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
nk_panel_layout(ctx, win, row_height, cols);
if (fmt == NK_DYNAMIC)
layout->row.type = NK_LAYOUT_DYNAMIC_ROW;
else layout->row.type = NK_LAYOUT_STATIC_ROW;
layout->row.ratio = 0;
layout->row.filled = 0;
layout->row.item_width = 0;
layout->row.item_offset = 0;
layout->row.columns = cols;
}
NK_API void
nk_layout_row_push(struct nk_context *ctx, float ratio_or_width)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
return;
if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {
float ratio = ratio_or_width;
if ((ratio + layout->row.filled) > 1.0f) return;
if (ratio > 0.0f)
layout->row.item_width = NK_SATURATE(ratio);
else layout->row.item_width = 1.0f - layout->row.filled;
} else layout->row.item_width = ratio_or_width;
}
NK_API void
nk_layout_row_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
return;
layout->row.item_width = 0;
layout->row.item_offset = 0;
}
NK_API void
nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,
float height, int cols, const float *ratio)
{
int i;
int n_undef = 0;
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
nk_panel_layout(ctx, win, height, cols);
if (fmt == NK_DYNAMIC) {
/* calculate width of undefined widget ratios */
float r = 0;
layout->row.ratio = ratio;
for (i = 0; i < cols; ++i) {
if (ratio[i] < 0.0f)
n_undef++;
else r += ratio[i];
}
r = NK_SATURATE(1.0f - r);
layout->row.type = NK_LAYOUT_DYNAMIC;
layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;
} else {
layout->row.ratio = ratio;
layout->row.type = NK_LAYOUT_STATIC;
layout->row.item_width = 0;
layout->row.item_offset = 0;
}
layout->row.item_offset = 0;
layout->row.filled = 0;
}
NK_API void
nk_layout_row_template_begin(struct nk_context *ctx, float height)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
nk_panel_layout(ctx, win, height, 1);
layout->row.type = NK_LAYOUT_TEMPLATE;
layout->row.columns = 0;
layout->row.ratio = 0;
layout->row.item_width = 0;
layout->row.item_height = 0;
layout->row.item_offset = 0;
layout->row.filled = 0;
layout->row.item.x = 0;
layout->row.item.y = 0;
layout->row.item.w = 0;
layout->row.item.h = 0;
}
NK_API void
nk_layout_row_template_push_dynamic(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
layout->row.templates[layout->row.columns++] = -1.0f;
}
NK_API void
nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
layout->row.templates[layout->row.columns++] = -min_width;
}
NK_API void
nk_layout_row_template_push_static(struct nk_context *ctx, float width)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
layout->row.templates[layout->row.columns++] = width;
}
NK_API void
nk_layout_row_template_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
int i = 0;
int variable_count = 0;
int min_variable_count = 0;
float min_fixed_width = 0.0f;
float total_fixed_width = 0.0f;
float max_variable_width = 0.0f;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
for (i = 0; i < layout->row.columns; ++i) {
float width = layout->row.templates[i];
if (width >= 0.0f) {
total_fixed_width += width;
min_fixed_width += width;
} else if (width < -1.0f) {
width = -width;
total_fixed_width += width;
max_variable_width = NK_MAX(max_variable_width, width);
variable_count++;
} else {
min_variable_count++;
variable_count++;
}
}
if (variable_count) {
float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
layout->bounds.w, layout->row.columns);
float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;
int enough_space = var_width >= max_variable_width;
if (!enough_space)
var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;
for (i = 0; i < layout->row.columns; ++i) {
float *width = &layout->row.templates[i];
*width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;
}
}
}
NK_API void
nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,
float height, int widget_count)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
nk_panel_layout(ctx, win, height, widget_count);
if (fmt == NK_STATIC)
layout->row.type = NK_LAYOUT_STATIC_FREE;
else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;
layout->row.ratio = 0;
layout->row.filled = 0;
layout->row.item_width = 0;
layout->row.item_offset = 0;
}
NK_API void
nk_layout_space_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
layout->row.item_width = 0;
layout->row.item_height = 0;
layout->row.item_offset = 0;
nk_zero(&layout->row.item, sizeof(layout->row.item));
}
NK_API void
nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
layout->row.item = rect;
}
NK_API struct nk_rect
nk_layout_space_bounds(struct nk_context *ctx)
{
struct nk_rect ret;
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x = layout->clip.x;
ret.y = layout->clip.y;
ret.w = layout->clip.w;
ret.h = layout->row.height;
return ret;
}
NK_API struct nk_rect
nk_layout_widget_bounds(struct nk_context *ctx)
{
struct nk_rect ret;
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x = layout->at_x;
ret.y = layout->at_y;
ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);
ret.h = layout->row.height;
return ret;
}
NK_API struct nk_vec2
nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x += layout->at_x - (float)*layout->offset_x;
ret.y += layout->at_y - (float)*layout->offset_y;
return ret;
}
NK_API struct nk_vec2
nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x += -layout->at_x + (float)*layout->offset_x;
ret.y += -layout->at_y + (float)*layout->offset_y;
return ret;
}
NK_API struct nk_rect
nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x += layout->at_x - (float)*layout->offset_x;
ret.y += layout->at_y - (float)*layout->offset_y;
return ret;
}
NK_API struct nk_rect
nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
win = ctx->current;
layout = win->layout;
ret.x += -layout->at_x + (float)*layout->offset_x;
ret.y += -layout->at_y + (float)*layout->offset_y;
return ret;
}
NK_LIB void
nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)
{
struct nk_panel *layout = win->layout;
struct nk_vec2 spacing = ctx->style.window.spacing;
const float row_height = layout->row.height - spacing.y;
nk_panel_layout(ctx, win, row_height, layout->row.columns);
}
NK_LIB void
nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,
struct nk_window *win, int modify)
{
struct nk_panel *layout;
const struct nk_style *style;
struct nk_vec2 spacing;
struct nk_vec2 padding;
float item_offset = 0;
float item_width = 0;
float item_spacing = 0;
float panel_space = 0;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
style = &ctx->style;
NK_ASSERT(bounds);
spacing = style->window.spacing;
padding = nk_panel_get_padding(style, layout->type);
panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
layout->bounds.w, layout->row.columns);
/* calculate the width of one item inside the current layout space */
switch (layout->row.type) {
case NK_LAYOUT_DYNAMIC_FIXED: {
/* scaling fixed size widgets item width */
item_width = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;
item_offset = (float)layout->row.index * item_width;
item_spacing = (float)layout->row.index * spacing.x;
} break;
case NK_LAYOUT_DYNAMIC_ROW: {
/* scaling single ratio widget width */
item_width = layout->row.item_width * panel_space;
item_offset = layout->row.item_offset;
item_spacing = 0;
if (modify) {
layout->row.item_offset += item_width + spacing.x;
layout->row.filled += layout->row.item_width;
layout->row.index = 0;
}
} break;
case NK_LAYOUT_DYNAMIC_FREE: {
/* panel width depended free widget placing */
bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);
bounds->x -= (float)*layout->offset_x;
bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);
bounds->y -= (float)*layout->offset_y;
bounds->w = layout->bounds.w * layout->row.item.w;
bounds->h = layout->row.height * layout->row.item.h;
return;
}
case NK_LAYOUT_DYNAMIC: {
/* scaling arrays of panel width ratios for every widget */
float ratio;
NK_ASSERT(layout->row.ratio);
ratio = (layout->row.ratio[layout->row.index] < 0) ?
layout->row.item_width : layout->row.ratio[layout->row.index];
item_spacing = (float)layout->row.index * spacing.x;
item_width = (ratio * panel_space);
item_offset = layout->row.item_offset;
if (modify) {
layout->row.item_offset += item_width;
layout->row.filled += ratio;
}
} break;
case NK_LAYOUT_STATIC_FIXED: {
/* non-scaling fixed widgets item width */
item_width = layout->row.item_width;
item_offset = (float)layout->row.index * item_width;
item_spacing = (float)layout->row.index * spacing.x;
} break;
case NK_LAYOUT_STATIC_ROW: {
/* scaling single ratio widget width */
item_width = layout->row.item_width;
item_offset = layout->row.item_offset;
item_spacing = (float)layout->row.index * spacing.x;
if (modify) layout->row.item_offset += item_width;
} break;
case NK_LAYOUT_STATIC_FREE: {
/* free widget placing */
bounds->x = layout->at_x + layout->row.item.x;
bounds->w = layout->row.item.w;
if (((bounds->x + bounds->w) > layout->max_x) && modify)
layout->max_x = (bounds->x + bounds->w);
bounds->x -= (float)*layout->offset_x;
bounds->y = layout->at_y + layout->row.item.y;
bounds->y -= (float)*layout->offset_y;
bounds->h = layout->row.item.h;
return;
}
case NK_LAYOUT_STATIC: {
/* non-scaling array of panel pixel width for every widget */
item_spacing = (float)layout->row.index * spacing.x;
item_width = layout->row.ratio[layout->row.index];
item_offset = layout->row.item_offset;
if (modify) layout->row.item_offset += item_width;
} break;
case NK_LAYOUT_TEMPLATE: {
/* stretchy row layout with combined dynamic/static widget width*/
NK_ASSERT(layout->row.index < layout->row.columns);
NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
item_width = layout->row.templates[layout->row.index];
item_offset = layout->row.item_offset;
item_spacing = (float)layout->row.index * spacing.x;
if (modify) layout->row.item_offset += item_width;
} break;
default: NK_ASSERT(0); break;
};
/* set the bounds of the newly allocated widget */
bounds->w = item_width;
bounds->h = layout->row.height - spacing.y;
bounds->y = layout->at_y - (float)*layout->offset_y;
bounds->x = layout->at_x + item_offset + item_spacing + padding.x;
if (((bounds->x + bounds->w) > layout->max_x) && modify)
layout->max_x = bounds->x + bounds->w;
bounds->x -= (float)*layout->offset_x;
}
NK_LIB void
nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
/* check if the end of the row has been hit and begin new row if so */
win = ctx->current;
layout = win->layout;
if (layout->row.index >= layout->row.columns)
nk_panel_alloc_row(ctx, win);
/* calculate widget position and size */
nk_layout_widget_space(bounds, ctx, win, nk_true);
layout->row.index++;
}
NK_LIB void
nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx)
{
float y;
int index;
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
y = layout->at_y;
index = layout->row.index;
if (layout->row.index >= layout->row.columns) {
layout->at_y += layout->row.height;
layout->row.index = 0;
}
nk_layout_widget_space(bounds, ctx, win, nk_false);
if (!layout->row.index) {
bounds->x -= layout->row.item_offset;
}
layout->at_y = y;
layout->row.index = index;
}

81
src/nuklear_list_view.c Normal file
View File

@ -0,0 +1,81 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* LIST VIEW
*
* ===============================================================*/
NK_API int
nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,
const char *title, nk_flags flags, int row_height, int row_count)
{
int title_len;
nk_hash title_hash;
nk_uint *x_offset;
nk_uint *y_offset;
int result;
struct nk_window *win;
struct nk_panel *layout;
const struct nk_style *style;
struct nk_vec2 item_spacing;
NK_ASSERT(ctx);
NK_ASSERT(view);
NK_ASSERT(title);
if (!ctx || !view || !title) return 0;
win = ctx->current;
style = &ctx->style;
item_spacing = style->window.spacing;
row_height += NK_MAX(0, (int)item_spacing.y);
/* find persistent list view scrollbar offset */
title_len = (int)nk_strlen(title);
title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
x_offset = nk_find_value(win, title_hash);
if (!x_offset) {
x_offset = nk_add_value(ctx, win, title_hash, 0);
y_offset = nk_add_value(ctx, win, title_hash+1, 0);
NK_ASSERT(x_offset);
NK_ASSERT(y_offset);
if (!x_offset || !y_offset) return 0;
*x_offset = *y_offset = 0;
} else y_offset = nk_find_value(win, title_hash+1);
view->scroll_value = *y_offset;
view->scroll_pointer = y_offset;
*y_offset = 0;
result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
win = ctx->current;
layout = win->layout;
view->total_height = row_height * NK_MAX(row_count,1);
view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);
view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0);
view->end = view->begin + view->count;
view->ctx = ctx;
return result;
}
NK_API void
nk_list_view_end(struct nk_list_view *view)
{
struct nk_context *ctx;
struct nk_window *win;
struct nk_panel *layout;
NK_ASSERT(view);
NK_ASSERT(view->ctx);
NK_ASSERT(view->scroll_pointer);
if (!view || !view->ctx) return;
ctx = view->ctx;
win = ctx->current;
layout = win->layout;
layout->at_y = layout->bounds.y + (float)view->total_height;
*view->scroll_pointer = *view->scroll_pointer + view->scroll_value;
nk_group_end(view->ctx);
}

295
src/nuklear_math.c Normal file
View File

@ -0,0 +1,295 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* MATH
*
* ===============================================================*/
/* Since nuklear is supposed to work on all systems providing floating point
math without any dependencies I also had to implement my own math functions
for sqrt, sin and cos. Since the actual highly accurate implementations for
the standard library functions are quite complex and I do not need high
precision for my use cases I use approximations.
Sqrt
----
For square root nuklear uses the famous fast inverse square root:
https://en.wikipedia.org/wiki/Fast_inverse_square_root with
slightly tweaked magic constant. While on today's hardware it is
probably not faster it is still fast and accurate enough for
nuklear's use cases. IMPORTANT: this requires float format IEEE 754
Sine/Cosine
-----------
All constants inside both function are generated Remez's minimax
approximations for value range 0...2*PI. The reason why I decided to
approximate exactly that range is that nuklear only needs sine and
cosine to generate circles which only requires that exact range.
In addition I used Remez instead of Taylor for additional precision:
www.lolengine.net/blog/2011/12/21/better-function-approximations.
The tool I used to generate constants for both sine and cosine
(it can actually approximate a lot more functions) can be
found here: www.lolengine.net/wiki/oss/lolremez
*/
NK_LIB float
nk_inv_sqrt(float n)
{
float x2;
const float threehalfs = 1.5f;
union {nk_uint i; float f;} conv = {0};
conv.f = n;
x2 = n * 0.5f;
conv.i = 0x5f375A84 - (conv.i >> 1);
conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
return conv.f;
}
NK_LIB float
nk_sqrt(float x)
{
return x * nk_inv_sqrt(x);
}
NK_LIB float
nk_sin(float x)
{
NK_STORAGE const float a0 = +1.91059300966915117e-31f;
NK_STORAGE const float a1 = +1.00086760103908896f;
NK_STORAGE const float a2 = -1.21276126894734565e-2f;
NK_STORAGE const float a3 = -1.38078780785773762e-1f;
NK_STORAGE const float a4 = -2.67353392911981221e-2f;
NK_STORAGE const float a5 = +2.08026600266304389e-2f;
NK_STORAGE const float a6 = -3.03996055049204407e-3f;
NK_STORAGE const float a7 = +1.38235642404333740e-4f;
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
}
NK_LIB float
nk_cos(float x)
{
NK_STORAGE const float a0 = +1.00238601909309722f;
NK_STORAGE const float a1 = -3.81919947353040024e-2f;
NK_STORAGE const float a2 = -3.94382342128062756e-1f;
NK_STORAGE const float a3 = -1.18134036025221444e-1f;
NK_STORAGE const float a4 = +1.07123798512170878e-1f;
NK_STORAGE const float a5 = -1.86637164165180873e-2f;
NK_STORAGE const float a6 = +9.90140908664079833e-4f;
NK_STORAGE const float a7 = -5.23022132118824778e-14f;
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
}
NK_LIB nk_uint
nk_round_up_pow2(nk_uint v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
NK_LIB double
nk_pow(double x, int n)
{
/* check the sign of n */
double r = 1;
int plus = n >= 0;
n = (plus) ? n : -n;
while (n > 0) {
if ((n & 1) == 1)
r *= x;
n /= 2;
x *= x;
}
return plus ? r : 1.0 / r;
}
NK_LIB int
nk_ifloord(double x)
{
x = (double)((int)x - ((x < 0.0) ? 1 : 0));
return (int)x;
}
NK_LIB int
nk_ifloorf(float x)
{
x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
return (int)x;
}
NK_LIB int
nk_iceilf(float x)
{
if (x >= 0) {
int i = (int)x;
return (x > i) ? i+1: i;
} else {
int t = (int)x;
float r = x - (float)t;
return (r > 0.0f) ? t+1: t;
}
}
NK_LIB int
nk_log10(double n)
{
int neg;
int ret;
int exp = 0;
neg = (n < 0) ? 1 : 0;
ret = (neg) ? (int)-n : (int)n;
while ((ret / 10) > 0) {
ret /= 10;
exp++;
}
if (neg) exp = -exp;
return exp;
}
NK_API struct nk_rect
nk_get_null_rect(void)
{
return nk_null_rect;
}
NK_API struct nk_rect
nk_rect(float x, float y, float w, float h)
{
struct nk_rect r;
r.x = x; r.y = y;
r.w = w; r.h = h;
return r;
}
NK_API struct nk_rect
nk_recti(int x, int y, int w, int h)
{
struct nk_rect r;
r.x = (float)x;
r.y = (float)y;
r.w = (float)w;
r.h = (float)h;
return r;
}
NK_API struct nk_rect
nk_recta(struct nk_vec2 pos, struct nk_vec2 size)
{
return nk_rect(pos.x, pos.y, size.x, size.y);
}
NK_API struct nk_rect
nk_rectv(const float *r)
{
return nk_rect(r[0], r[1], r[2], r[3]);
}
NK_API struct nk_rect
nk_rectiv(const int *r)
{
return nk_recti(r[0], r[1], r[2], r[3]);
}
NK_API struct nk_vec2
nk_rect_pos(struct nk_rect r)
{
struct nk_vec2 ret;
ret.x = r.x; ret.y = r.y;
return ret;
}
NK_API struct nk_vec2
nk_rect_size(struct nk_rect r)
{
struct nk_vec2 ret;
ret.x = r.w; ret.y = r.h;
return ret;
}
NK_LIB struct nk_rect
nk_shrink_rect(struct nk_rect r, float amount)
{
struct nk_rect res;
r.w = NK_MAX(r.w, 2 * amount);
r.h = NK_MAX(r.h, 2 * amount);
res.x = r.x + amount;
res.y = r.y + amount;
res.w = r.w - 2 * amount;
res.h = r.h - 2 * amount;
return res;
}
NK_LIB struct nk_rect
nk_pad_rect(struct nk_rect r, struct nk_vec2 pad)
{
r.w = NK_MAX(r.w, 2 * pad.x);
r.h = NK_MAX(r.h, 2 * pad.y);
r.x += pad.x; r.y += pad.y;
r.w -= 2 * pad.x;
r.h -= 2 * pad.y;
return r;
}
NK_API struct nk_vec2
nk_vec2(float x, float y)
{
struct nk_vec2 ret;
ret.x = x; ret.y = y;
return ret;
}
NK_API struct nk_vec2
nk_vec2i(int x, int y)
{
struct nk_vec2 ret;
ret.x = (float)x;
ret.y = (float)y;
return ret;
}
NK_API struct nk_vec2
nk_vec2v(const float *v)
{
return nk_vec2(v[0], v[1]);
}
NK_API struct nk_vec2
nk_vec2iv(const int *v)
{
return nk_vec2i(v[0], v[1]);
}
NK_LIB void
nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,
float x1, float y1)
{
NK_ASSERT(a);
NK_ASSERT(clip);
clip->x = NK_MAX(a->x, x0);
clip->y = NK_MAX(a->y, y0);
clip->w = NK_MIN(a->x + a->w, x1) - clip->x;
clip->h = NK_MIN(a->y + a->h, y1) - clip->y;
clip->w = NK_MAX(0, clip->w);
clip->h = NK_MAX(0, clip->h);
}
NK_API void
nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,
float pad_x, float pad_y, enum nk_heading direction)
{
float w_half, h_half;
NK_ASSERT(result);
r.w = NK_MAX(2 * pad_x, r.w);
r.h = NK_MAX(2 * pad_y, r.h);
r.w = r.w - 2 * pad_x;
r.h = r.h - 2 * pad_y;
r.x = r.x + pad_x;
r.y = r.y + pad_y;
w_half = r.w / 2.0f;
h_half = r.h / 2.0f;
if (direction == NK_UP) {
result[0] = nk_vec2(r.x + w_half, r.y);
result[1] = nk_vec2(r.x + r.w, r.y + r.h);
result[2] = nk_vec2(r.x, r.y + r.h);
} else if (direction == NK_RIGHT) {
result[0] = nk_vec2(r.x, r.y);
result[1] = nk_vec2(r.x + r.w, r.y + h_half);
result[2] = nk_vec2(r.x, r.y + r.h);
} else if (direction == NK_DOWN) {
result[0] = nk_vec2(r.x, r.y);
result[1] = nk_vec2(r.x + r.w, r.y);
result[2] = nk_vec2(r.x + w_half, r.y + r.h);
} else {
result[0] = nk_vec2(r.x, r.y + h_half);
result[1] = nk_vec2(r.x + r.w, r.y);
result[2] = nk_vec2(r.x + r.w, r.y + r.h);
}
}

295
src/nuklear_menu.c Normal file
View File

@ -0,0 +1,295 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* MENU
*
* ===============================================================*/
NK_API void
nk_menubar_begin(struct nk_context *ctx)
{
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
layout = ctx->current->layout;
NK_ASSERT(layout->at_y == layout->bounds.y);
/* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.
If you want a menubar the first nuklear function after `nk_begin` has to be a
`nk_menubar_begin` call. Inside the menubar you then have to allocate space for
widgets (also supports multiple rows).
Example:
if (nk_begin(...)) {
nk_menubar_begin(...);
nk_layout_xxxx(...);
nk_button(...);
nk_layout_xxxx(...);
nk_button(...);
nk_menubar_end(...);
}
nk_end(...);
*/
if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
return;
layout->menu.x = layout->at_x;
layout->menu.y = layout->at_y + layout->row.height;
layout->menu.w = layout->bounds.w;
layout->menu.offset.x = *layout->offset_x;
layout->menu.offset.y = *layout->offset_y;
*layout->offset_y = 0;
}
NK_API void
nk_menubar_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_panel *layout;
struct nk_command_buffer *out;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
out = &win->buffer;
layout = win->layout;
if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
return;
layout->menu.h = layout->at_y - layout->menu.y;
layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
*layout->offset_x = layout->menu.offset.x;
*layout->offset_y = layout->menu.offset.y;
layout->at_y = layout->bounds.y - layout->row.height;
layout->clip.y = layout->bounds.y;
layout->clip.h = layout->bounds.h;
nk_push_scissor(out, layout->clip);
}
NK_INTERN int
nk_menu_begin(struct nk_context *ctx, struct nk_window *win,
const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)
{
int is_open = 0;
int is_active = 0;
struct nk_rect body;
struct nk_window *popup;
nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
body.x = header.x;
body.w = size.x;
body.y = header.y + header.h;
body.h = size.y;
popup = win->popup.win;
is_open = popup ? nk_true : nk_false;
is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);
if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
(!is_open && !is_active && !is_clicked)) return 0;
if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))
return 0;
win->popup.type = NK_PANEL_MENU;
win->popup.name = hash;
return 1;
}
NK_API int
nk_menu_begin_text(struct nk_context *ctx, const char *title, int len,
nk_flags align, struct nk_vec2 size)
{
struct nk_window *win;
const struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
nk_flags state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
state = nk_widget(&header, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,
title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
is_clicked = nk_true;
return nk_menu_begin(ctx, win, title, is_clicked, header, size);
}
NK_API int nk_menu_begin_label(struct nk_context *ctx,
const char *text, nk_flags align, struct nk_vec2 size)
{
return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);
}
NK_API int
nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,
struct nk_vec2 size)
{
struct nk_window *win;
struct nk_rect header;
const struct nk_input *in;
int is_clicked = nk_false;
nk_flags state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
state = nk_widget(&header, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,
img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))
is_clicked = nk_true;
return nk_menu_begin(ctx, win, id, is_clicked, header, size);
}
NK_API int
nk_menu_begin_symbol(struct nk_context *ctx, const char *id,
enum nk_symbol_type sym, struct nk_vec2 size)
{
struct nk_window *win;
const struct nk_input *in;
struct nk_rect header;
int is_clicked = nk_false;
nk_flags state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
state = nk_widget(&header, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header,
sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
is_clicked = nk_true;
return nk_menu_begin(ctx, win, id, is_clicked, header, size);
}
NK_API int
nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,
nk_flags align, struct nk_image img, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_rect header;
const struct nk_input *in;
int is_clicked = nk_false;
nk_flags state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
state = nk_widget(&header, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
ctx->style.font, in))
is_clicked = nk_true;
return nk_menu_begin(ctx, win, title, is_clicked, header, size);
}
NK_API int
nk_menu_begin_image_label(struct nk_context *ctx,
const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)
{
return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);
}
NK_API int
nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,
nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)
{
struct nk_window *win;
struct nk_rect header;
const struct nk_input *in;
int is_clicked = nk_false;
nk_flags state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
state = nk_widget(&header, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,
header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
ctx->style.font, in)) is_clicked = nk_true;
return nk_menu_begin(ctx, win, title, is_clicked, header, size);
}
NK_API int
nk_menu_begin_symbol_label(struct nk_context *ctx,
const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )
{
return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);
}
NK_API int
nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)
{
return nk_contextual_item_text(ctx, title, len, align);
}
NK_API int
nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)
{
return nk_contextual_item_label(ctx, label, align);
}
NK_API int
nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,
const char *label, nk_flags align)
{
return nk_contextual_item_image_label(ctx, img, label, align);
}
NK_API int
nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,
const char *text, int len, nk_flags align)
{
return nk_contextual_item_image_text(ctx, img, text, len, align);
}
NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
const char *text, int len, nk_flags align)
{
return nk_contextual_item_symbol_text(ctx, sym, text, len, align);
}
NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
const char *label, nk_flags align)
{
return nk_contextual_item_symbol_label(ctx, sym, label, align);
}
NK_API void nk_menu_close(struct nk_context *ctx)
{
nk_contextual_close(ctx);
}
NK_API void
nk_menu_end(struct nk_context *ctx)
{
nk_contextual_end(ctx);
}

View File

@ -0,0 +1,62 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PAGE ELEMENT
*
* ===============================================================*/
NK_LIB struct nk_page_element*
nk_create_page_element(struct nk_context *ctx)
{
struct nk_page_element *elem;
if (ctx->freelist) {
/* unlink page element from free list */
elem = ctx->freelist;
ctx->freelist = elem->next;
} else if (ctx->use_pool) {
/* allocate page element from memory pool */
elem = nk_pool_alloc(&ctx->pool);
NK_ASSERT(elem);
if (!elem) return 0;
} else {
/* allocate new page element from back of fixed size memory buffer */
NK_STORAGE const nk_size size = sizeof(struct nk_page_element);
NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);
elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);
NK_ASSERT(elem);
if (!elem) return 0;
}
nk_zero_struct(*elem);
elem->next = 0;
elem->prev = 0;
return elem;
}
NK_LIB void
nk_link_page_element_into_freelist(struct nk_context *ctx,
struct nk_page_element *elem)
{
/* link table into freelist */
if (!ctx->freelist) {
ctx->freelist = elem;
} else {
elem->next = ctx->freelist;
ctx->freelist = elem;
}
}
NK_LIB void
nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)
{
/* we have a pool so just add to free list */
if (ctx->use_pool) {
nk_link_page_element_into_freelist(ctx, elem);
return;
}
/* if possible remove last element from back of fixed memory buffer */
{void *elem_end = (void*)(elem + 1);
void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;
if (elem_end == buffer_end)
ctx->memory.size -= sizeof(struct nk_page_element);
else nk_link_page_element_into_freelist(ctx, elem);}
}

602
src/nuklear_panel.c Normal file
View File

@ -0,0 +1,602 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PANEL
*
* ===============================================================*/
NK_LIB void*
nk_create_panel(struct nk_context *ctx)
{
struct nk_page_element *elem;
elem = nk_create_page_element(ctx);
if (!elem) return 0;
nk_zero_struct(*elem);
return &elem->data.pan;
}
NK_LIB void
nk_free_panel(struct nk_context *ctx, struct nk_panel *pan)
{
union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);
struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
nk_free_page_element(ctx, pe);
}
NK_LIB int
nk_panel_has_header(nk_flags flags, const char *title)
{
int active = 0;
active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));
active = active || (flags & NK_WINDOW_TITLE);
active = active && !(flags & NK_WINDOW_HIDDEN) && title;
return active;
}
NK_LIB struct nk_vec2
nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)
{
switch (type) {
default:
case NK_PANEL_WINDOW: return style->window.padding;
case NK_PANEL_GROUP: return style->window.group_padding;
case NK_PANEL_POPUP: return style->window.popup_padding;
case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;
case NK_PANEL_COMBO: return style->window.combo_padding;
case NK_PANEL_MENU: return style->window.menu_padding;
case NK_PANEL_TOOLTIP: return style->window.menu_padding;}
}
NK_LIB float
nk_panel_get_border(const struct nk_style *style, nk_flags flags,
enum nk_panel_type type)
{
if (flags & NK_WINDOW_BORDER) {
switch (type) {
default:
case NK_PANEL_WINDOW: return style->window.border;
case NK_PANEL_GROUP: return style->window.group_border;
case NK_PANEL_POPUP: return style->window.popup_border;
case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;
case NK_PANEL_COMBO: return style->window.combo_border;
case NK_PANEL_MENU: return style->window.menu_border;
case NK_PANEL_TOOLTIP: return style->window.menu_border;
}} else return 0;
}
NK_LIB struct nk_color
nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)
{
switch (type) {
default:
case NK_PANEL_WINDOW: return style->window.border_color;
case NK_PANEL_GROUP: return style->window.group_border_color;
case NK_PANEL_POPUP: return style->window.popup_border_color;
case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;
case NK_PANEL_COMBO: return style->window.combo_border_color;
case NK_PANEL_MENU: return style->window.menu_border_color;
case NK_PANEL_TOOLTIP: return style->window.menu_border_color;}
}
NK_LIB int
nk_panel_is_sub(enum nk_panel_type type)
{
return (type & NK_PANEL_SET_SUB)?1:0;
}
NK_LIB int
nk_panel_is_nonblock(enum nk_panel_type type)
{
return (type & NK_PANEL_SET_NONBLOCK)?1:0;
}
NK_LIB int
nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)
{
struct nk_input *in;
struct nk_window *win;
struct nk_panel *layout;
struct nk_command_buffer *out;
const struct nk_style *style;
const struct nk_user_font *font;
struct nk_vec2 scrollbar_size;
struct nk_vec2 panel_padding;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return 0;
nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));
if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {
nk_zero(ctx->current->layout, sizeof(struct nk_panel));
ctx->current->layout->type = panel_type;
return 0;
}
/* pull state into local stack */
style = &ctx->style;
font = style->font;
win = ctx->current;
layout = win->layout;
out = &win->buffer;
in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;
#ifdef NK_INCLUDE_COMMAND_USERDATA
win->buffer.userdata = ctx->userdata;
#endif
/* pull style configuration into local stack */
scrollbar_size = style->window.scrollbar_size;
panel_padding = nk_panel_get_padding(style, panel_type);
/* window movement */
if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {
int left_mouse_down;
int left_mouse_click_in_cursor;
/* calculate draggable window space */
struct nk_rect header;
header.x = win->bounds.x;
header.y = win->bounds.y;
header.w = win->bounds.w;
if (nk_panel_has_header(win->flags, title)) {
header.h = font->height + 2.0f * style->window.header.padding.y;
header.h += 2.0f * style->window.header.label_padding.y;
} else header.h = panel_padding.y;
/* window movement by dragging */
left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
NK_BUTTON_LEFT, header, nk_true);
if (left_mouse_down && left_mouse_click_in_cursor) {
win->bounds.x = win->bounds.x + in->mouse.delta.x;
win->bounds.y = win->bounds.y + in->mouse.delta.y;
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];
}
}
/* setup panel */
layout->type = panel_type;
layout->flags = win->flags;
layout->bounds = win->bounds;
layout->bounds.x += panel_padding.x;
layout->bounds.w -= 2*panel_padding.x;
if (win->flags & NK_WINDOW_BORDER) {
layout->border = nk_panel_get_border(style, win->flags, panel_type);
layout->bounds = nk_shrink_rect(layout->bounds, layout->border);
} else layout->border = 0;
layout->at_y = layout->bounds.y;
layout->at_x = layout->bounds.x;
layout->max_x = 0;
layout->header_height = 0;
layout->footer_height = 0;
nk_layout_reset_min_row_height(ctx);
layout->row.index = 0;
layout->row.columns = 0;
layout->row.ratio = 0;
layout->row.item_width = 0;
layout->row.tree_depth = 0;
layout->row.height = panel_padding.y;
layout->has_scrolling = nk_true;
if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))
layout->bounds.w -= scrollbar_size.x;
if (!nk_panel_is_nonblock(panel_type)) {
layout->footer_height = 0;
if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)
layout->footer_height = scrollbar_size.y;
layout->bounds.h -= layout->footer_height;
}
/* panel header */
if (nk_panel_has_header(win->flags, title))
{
struct nk_text text;
struct nk_rect header;
const struct nk_style_item *background = 0;
/* calculate header bounds */
header.x = win->bounds.x;
header.y = win->bounds.y;
header.w = win->bounds.w;
header.h = font->height + 2.0f * style->window.header.padding.y;
header.h += (2.0f * style->window.header.label_padding.y);
/* shrink panel by header */
layout->header_height = header.h;
layout->bounds.y += header.h;
layout->bounds.h -= header.h;
layout->at_y += header.h;
/* select correct header background and text color */
if (ctx->active == win) {
background = &style->window.header.active;
text.text = style->window.header.label_active;
} else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {
background = &style->window.header.hover;
text.text = style->window.header.label_hover;
} else {
background = &style->window.header.normal;
text.text = style->window.header.label_normal;
}
/* draw header background */
header.h += 1.0f;
if (background->type == NK_STYLE_ITEM_IMAGE) {
text.background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
} else {
text.background = background->data.color;
nk_fill_rect(out, header, 0, background->data.color);
}
/* window close button */
{struct nk_rect button;
button.y = header.y + style->window.header.padding.y;
button.h = header.h - 2 * style->window.header.padding.y;
button.w = button.h;
if (win->flags & NK_WINDOW_CLOSABLE) {
nk_flags ws = 0;
if (style->window.header.align == NK_HEADER_RIGHT) {
button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);
header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;
} else {
button.x = header.x + style->window.header.padding.x;
header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
}
if (nk_do_button_symbol(&ws, &win->buffer, button,
style->window.header.close_symbol, NK_BUTTON_DEFAULT,
&style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
{
layout->flags |= NK_WINDOW_HIDDEN;
layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;
}
}
/* window minimize button */
if (win->flags & NK_WINDOW_MINIMIZABLE) {
nk_flags ws = 0;
if (style->window.header.align == NK_HEADER_RIGHT) {
button.x = (header.w + header.x) - button.w;
if (!(win->flags & NK_WINDOW_CLOSABLE)) {
button.x -= style->window.header.padding.x;
header.w -= style->window.header.padding.x;
}
header.w -= button.w + style->window.header.spacing.x;
} else {
button.x = header.x;
header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
}
if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?
style->window.header.maximize_symbol: style->window.header.minimize_symbol,
NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?
layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:
layout->flags | NK_WINDOW_MINIMIZED;
}}
{/* window header title */
int text_len = nk_strlen(title);
struct nk_rect label = {0,0,0,0};
float t = font->width(font->userdata, font->height, title, text_len);
text.padding = nk_vec2(0,0);
label.x = header.x + style->window.header.padding.x;
label.x += style->window.header.label_padding.x;
label.y = header.y + style->window.header.label_padding.y;
label.h = font->height + 2 * style->window.header.label_padding.y;
label.w = t + 2 * style->window.header.spacing.x;
label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);
nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);}
}
/* draw window background */
if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {
struct nk_rect body;
body.x = win->bounds.x;
body.w = win->bounds.w;
body.y = (win->bounds.y + layout->header_height);
body.h = (win->bounds.h - layout->header_height);
if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE)
nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);
else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color);
}
/* set clipping rectangle */
{struct nk_rect clip;
layout->clip = layout->bounds;
nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,
layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);
nk_push_scissor(out, clip);
layout->clip = clip;}
return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);
}
NK_LIB void
nk_panel_end(struct nk_context *ctx)
{
struct nk_input *in;
struct nk_window *window;
struct nk_panel *layout;
const struct nk_style *style;
struct nk_command_buffer *out;
struct nk_vec2 scrollbar_size;
struct nk_vec2 panel_padding;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
window = ctx->current;
layout = window->layout;
style = &ctx->style;
out = &window->buffer;
in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;
if (!nk_panel_is_sub(layout->type))
nk_push_scissor(out, nk_null_rect);
/* cache configuration data */
scrollbar_size = style->window.scrollbar_size;
panel_padding = nk_panel_get_padding(style, layout->type);
/* update the current cursor Y-position to point over the last added widget */
layout->at_y += layout->row.height;
/* dynamic panels */
if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))
{
/* update panel height to fit dynamic growth */
struct nk_rect empty_space;
if (layout->at_y < (layout->bounds.y + layout->bounds.h))
layout->bounds.h = layout->at_y - layout->bounds.y;
/* fill top empty space */
empty_space.x = window->bounds.x;
empty_space.y = layout->bounds.y;
empty_space.h = panel_padding.y;
empty_space.w = window->bounds.w;
nk_fill_rect(out, empty_space, 0, style->window.background);
/* fill left empty space */
empty_space.x = window->bounds.x;
empty_space.y = layout->bounds.y;
empty_space.w = panel_padding.x + layout->border;
empty_space.h = layout->bounds.h;
nk_fill_rect(out, empty_space, 0, style->window.background);
/* fill right empty space */
empty_space.x = layout->bounds.x + layout->bounds.w - layout->border;
empty_space.y = layout->bounds.y;
empty_space.w = panel_padding.x + layout->border;
empty_space.h = layout->bounds.h;
if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))
empty_space.w += scrollbar_size.x;
nk_fill_rect(out, empty_space, 0, style->window.background);
/* fill bottom empty space */
if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) {
empty_space.x = window->bounds.x;
empty_space.y = layout->bounds.y + layout->bounds.h;
empty_space.w = window->bounds.w;
empty_space.h = scrollbar_size.y;
nk_fill_rect(out, empty_space, 0, style->window.background);
}
}
/* scrollbars */
if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&
!(layout->flags & NK_WINDOW_MINIMIZED) &&
window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)
{
struct nk_rect scroll;
int scroll_has_scrolling;
float scroll_target;
float scroll_offset;
float scroll_step;
float scroll_inc;
/* mouse wheel scrolling */
if (nk_panel_is_sub(layout->type))
{
/* sub-window mouse wheel scrolling */
struct nk_window *root_window = window;
struct nk_panel *root_panel = window->layout;
while (root_panel->parent)
root_panel = root_panel->parent;
while (root_window->parent)
root_window = root_window->parent;
/* only allow scrolling if parent window is active */
scroll_has_scrolling = 0;
if ((root_window == ctx->active) && layout->has_scrolling) {
/* and panel is being hovered and inside clip rect*/
if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&
NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,
root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))
{
/* deactivate all parent scrolling */
root_panel = window->layout;
while (root_panel->parent) {
root_panel->has_scrolling = nk_false;
root_panel = root_panel->parent;
}
root_panel->has_scrolling = nk_false;
scroll_has_scrolling = nk_true;
}
}
} else if (!nk_panel_is_sub(layout->type)) {
/* window mouse wheel scrolling */
scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;
if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)
window->scrolled = nk_true;
else window->scrolled = nk_false;
} else scroll_has_scrolling = nk_false;
{
/* vertical scrollbar */
nk_flags state = 0;
scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
scroll.y = layout->bounds.y;
scroll.w = scrollbar_size.x;
scroll.h = layout->bounds.h;
scroll_offset = (float)*layout->offset_y;
scroll_step = scroll.h * 0.10f;
scroll_inc = scroll.h * 0.01f;
scroll_target = (float)(int)(layout->at_y - scroll.y);
scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,
scroll_offset, scroll_target, scroll_step, scroll_inc,
&ctx->style.scrollv, in, style->font);
*layout->offset_y = (nk_uint)scroll_offset;
if (in && scroll_has_scrolling)
in->mouse.scroll_delta.y = 0;
}
{
/* horizontal scrollbar */
nk_flags state = 0;
scroll.x = layout->bounds.x;
scroll.y = layout->bounds.y + layout->bounds.h;
scroll.w = layout->bounds.w;
scroll.h = scrollbar_size.y;
scroll_offset = (float)*layout->offset_x;
scroll_target = (float)(int)(layout->max_x - scroll.x);
scroll_step = layout->max_x * 0.05f;
scroll_inc = layout->max_x * 0.005f;
scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,
scroll_offset, scroll_target, scroll_step, scroll_inc,
&ctx->style.scrollh, in, style->font);
*layout->offset_x = (nk_uint)scroll_offset;
}
}
/* hide scroll if no user input */
if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {
int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0;
int is_window_hovered = nk_window_is_hovered(ctx);
int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))
window->scrollbar_hiding_timer += ctx->delta_time_seconds;
else window->scrollbar_hiding_timer = 0;
} else window->scrollbar_hiding_timer = 0;
/* window border */
if (layout->flags & NK_WINDOW_BORDER)
{
struct nk_color border_color = nk_panel_get_border_color(style, layout->type);
const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED)
? (style->window.border + window->bounds.y + layout->header_height)
: ((layout->flags & NK_WINDOW_DYNAMIC)
? (layout->bounds.y + layout->bounds.h + layout->footer_height)
: (window->bounds.y + window->bounds.h));
struct nk_rect b = window->bounds;
b.h = padding_y - window->bounds.y;
nk_stroke_rect(out, b, 0, layout->border, border_color);
}
/* scaler */
if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))
{
/* calculate scaler bounds */
struct nk_rect scaler;
scaler.w = scrollbar_size.x;
scaler.h = scrollbar_size.y;
scaler.y = layout->bounds.y + layout->bounds.h;
if (layout->flags & NK_WINDOW_SCALE_LEFT)
scaler.x = layout->bounds.x - panel_padding.x * 0.5f;
else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
if (layout->flags & NK_WINDOW_NO_SCROLLBAR)
scaler.x -= scaler.w;
/* draw scaler */
{const struct nk_style_item *item = &style->window.scaler;
if (item->type == NK_STYLE_ITEM_IMAGE)
nk_draw_image(out, scaler, &item->data.image, nk_white);
else {
if (layout->flags & NK_WINDOW_SCALE_LEFT) {
nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,
scaler.y + scaler.h, scaler.x + scaler.w,
scaler.y + scaler.h, item->data.color);
} else {
nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,
scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);
}
}}
/* do window scaling */
if (!(window->flags & NK_WINDOW_ROM)) {
struct nk_vec2 window_size = style->window.min_size;
int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,
NK_BUTTON_LEFT, scaler, nk_true);
if (left_mouse_down && left_mouse_click_in_scaler) {
float delta_x = in->mouse.delta.x;
if (layout->flags & NK_WINDOW_SCALE_LEFT) {
delta_x = -delta_x;
window->bounds.x += in->mouse.delta.x;
}
/* dragging in x-direction */
if (window->bounds.w + delta_x >= window_size.x) {
if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) {
window->bounds.w = window->bounds.w + delta_x;
scaler.x += in->mouse.delta.x;
}
}
/* dragging in y-direction (only possible if static window) */
if (!(layout->flags & NK_WINDOW_DYNAMIC)) {
if (window_size.y < window->bounds.h + in->mouse.delta.y) {
if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) {
window->bounds.h = window->bounds.h + in->mouse.delta.y;
scaler.y += in->mouse.delta.y;
}
}
}
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;
}
}
}
if (!nk_panel_is_sub(layout->type)) {
/* window is hidden so clear command buffer */
if (layout->flags & NK_WINDOW_HIDDEN)
nk_command_buffer_reset(&window->buffer);
/* window is visible and not tab */
else nk_finish(ctx, window);
}
/* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */
if (layout->flags & NK_WINDOW_REMOVE_ROM) {
layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
}
window->flags = layout->flags;
/* property garbage collector */
if (window->property.active && window->property.old != window->property.seq &&
window->property.active == window->property.prev) {
nk_zero(&window->property, sizeof(window->property));
} else {
window->property.old = window->property.seq;
window->property.prev = window->property.active;
window->property.seq = 0;
}
/* edit garbage collector */
if (window->edit.active && window->edit.old != window->edit.seq &&
window->edit.active == window->edit.prev) {
nk_zero(&window->edit, sizeof(window->edit));
} else {
window->edit.old = window->edit.seq;
window->edit.prev = window->edit.active;
window->edit.seq = 0;
}
/* contextual garbage collector */
if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {
window->popup.con_count = 0;
window->popup.con_old = 0;
window->popup.active_con = 0;
} else {
window->popup.con_old = window->popup.con_count;
window->popup.con_count = 0;
}
window->popup.combo_count = 0;
/* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */
NK_ASSERT(!layout->row.tree_depth);
}

63
src/nuklear_pool.c Normal file
View File

@ -0,0 +1,63 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* POOL
*
* ===============================================================*/
NK_LIB void
nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc,
unsigned int capacity)
{
nk_zero(pool, sizeof(*pool));
pool->alloc = *alloc;
pool->capacity = capacity;
pool->type = NK_BUFFER_DYNAMIC;
pool->pages = 0;
}
NK_LIB void
nk_pool_free(struct nk_pool *pool)
{
struct nk_page *iter = pool->pages;
if (!pool) return;
if (pool->type == NK_BUFFER_FIXED) return;
while (iter) {
struct nk_page *next = iter->next;
pool->alloc.free(pool->alloc.userdata, iter);
iter = next;
}
}
NK_LIB void
nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)
{
nk_zero(pool, sizeof(*pool));
NK_ASSERT(size >= sizeof(struct nk_page));
if (size < sizeof(struct nk_page)) return;
pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element);
pool->pages = (struct nk_page*)memory;
pool->type = NK_BUFFER_FIXED;
pool->size = size;
}
NK_LIB struct nk_page_element*
nk_pool_alloc(struct nk_pool *pool)
{
if (!pool->pages || pool->pages->size >= pool->capacity) {
/* allocate new page */
struct nk_page *page;
if (pool->type == NK_BUFFER_FIXED) {
NK_ASSERT(pool->pages);
if (!pool->pages) return 0;
NK_ASSERT(pool->pages->size < pool->capacity);
return 0;
} else {
nk_size size = sizeof(struct nk_page);
size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data);
page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);
page->next = pool->pages;
pool->pages = page;
page->size = 0;
}
} return &pool->pages->win[pool->pages->size++];
}

228
src/nuklear_popup.c Normal file
View File

@ -0,0 +1,228 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* POPUP
*
* ===============================================================*/
NK_API int
nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,
const char *title, nk_flags flags, struct nk_rect rect)
{
struct nk_window *popup;
struct nk_window *win;
struct nk_panel *panel;
int title_len;
nk_hash title_hash;
nk_size allocated;
NK_ASSERT(ctx);
NK_ASSERT(title);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
win = ctx->current;
panel = win->layout;
NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups");
(void)panel;
title_len = (int)nk_strlen(title);
title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);
popup = win->popup.win;
if (!popup) {
popup = (struct nk_window*)nk_create_window(ctx);
popup->parent = win;
win->popup.win = popup;
win->popup.active = 0;
win->popup.type = NK_PANEL_POPUP;
}
/* make sure we have correct popup */
if (win->popup.name != title_hash) {
if (!win->popup.active) {
nk_zero(popup, sizeof(*popup));
win->popup.name = title_hash;
win->popup.active = 1;
win->popup.type = NK_PANEL_POPUP;
} else return 0;
}
/* popup position is local to window */
ctx->current = popup;
rect.x += win->layout->clip.x;
rect.y += win->layout->clip.y;
/* setup popup data */
popup->parent = win;
popup->bounds = rect;
popup->seq = ctx->seq;
popup->layout = (struct nk_panel*)nk_create_panel(ctx);
popup->flags = flags;
popup->flags |= NK_WINDOW_BORDER;
if (type == NK_POPUP_DYNAMIC)
popup->flags |= NK_WINDOW_DYNAMIC;
popup->buffer = win->buffer;
nk_start_popup(ctx, win);
allocated = ctx->memory.allocated;
nk_push_scissor(&popup->buffer, nk_null_rect);
if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {
/* popup is running therefore invalidate parent panels */
struct nk_panel *root;
root = win->layout;
while (root) {
root->flags |= NK_WINDOW_ROM;
root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
root = root->parent;
}
win->popup.active = 1;
popup->layout->offset_x = &popup->scrollbar.x;
popup->layout->offset_y = &popup->scrollbar.y;
popup->layout->parent = win->layout;
return 1;
} else {
/* popup was closed/is invalid so cleanup */
struct nk_panel *root;
root = win->layout;
while (root) {
root->flags |= NK_WINDOW_REMOVE_ROM;
root = root->parent;
}
win->popup.buf.active = 0;
win->popup.active = 0;
ctx->memory.allocated = allocated;
ctx->current = win;
nk_free_panel(ctx, popup->layout);
popup->layout = 0;
return 0;
}
}
NK_LIB int
nk_nonblock_begin(struct nk_context *ctx,
nk_flags flags, struct nk_rect body, struct nk_rect header,
enum nk_panel_type panel_type)
{
struct nk_window *popup;
struct nk_window *win;
struct nk_panel *panel;
int is_active = nk_true;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
/* popups cannot have popups */
win = ctx->current;
panel = win->layout;
NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP));
(void)panel;
popup = win->popup.win;
if (!popup) {
/* create window for nonblocking popup */
popup = (struct nk_window*)nk_create_window(ctx);
popup->parent = win;
win->popup.win = popup;
win->popup.type = panel_type;
nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);
} else {
/* close the popup if user pressed outside or in the header */
int pressed, in_body, in_header;
pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);
if (pressed && (!in_body || in_header))
is_active = nk_false;
}
win->popup.header = header;
if (!is_active) {
/* remove read only mode from all parent panels */
struct nk_panel *root = win->layout;
while (root) {
root->flags |= NK_WINDOW_REMOVE_ROM;
root = root->parent;
}
return is_active;
}
popup->bounds = body;
popup->parent = win;
popup->layout = (struct nk_panel*)nk_create_panel(ctx);
popup->flags = flags;
popup->flags |= NK_WINDOW_BORDER;
popup->flags |= NK_WINDOW_DYNAMIC;
popup->seq = ctx->seq;
win->popup.active = 1;
NK_ASSERT(popup->layout);
nk_start_popup(ctx, win);
popup->buffer = win->buffer;
nk_push_scissor(&popup->buffer, nk_null_rect);
ctx->current = popup;
nk_panel_begin(ctx, 0, panel_type);
win->buffer = popup->buffer;
popup->layout->parent = win->layout;
popup->layout->offset_x = &popup->scrollbar.x;
popup->layout->offset_y = &popup->scrollbar.y;
/* set read only mode to all parent panels */
{struct nk_panel *root;
root = win->layout;
while (root) {
root->flags |= NK_WINDOW_ROM;
root = root->parent;
}}
return is_active;
}
NK_API void
nk_popup_close(struct nk_context *ctx)
{
struct nk_window *popup;
NK_ASSERT(ctx);
if (!ctx || !ctx->current) return;
popup = ctx->current;
NK_ASSERT(popup->parent);
NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP);
popup->flags |= NK_WINDOW_HIDDEN;
}
NK_API void
nk_popup_end(struct nk_context *ctx)
{
struct nk_window *win;
struct nk_window *popup;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
popup = ctx->current;
if (!popup->parent) return;
win = popup->parent;
if (popup->flags & NK_WINDOW_HIDDEN) {
struct nk_panel *root;
root = win->layout;
while (root) {
root->flags |= NK_WINDOW_REMOVE_ROM;
root = root->parent;
}
win->popup.active = 0;
}
nk_push_scissor(&popup->buffer, nk_null_rect);
nk_end(ctx);
win->buffer = popup->buffer;
nk_finish_popup(ctx, win);
ctx->current = win;
nk_push_scissor(&win->buffer, win->layout->clip);
}

142
src/nuklear_progress.c Normal file
View File

@ -0,0 +1,142 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PROGRESS
*
* ===============================================================*/
NK_LIB nk_size
nk_progress_behavior(nk_flags *state, struct nk_input *in,
struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, int modifiable)
{
int left_mouse_down = 0;
int left_mouse_click_in_cursor = 0;
nk_widget_state_reset(state);
if (!in || !modifiable) return value;
left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
NK_BUTTON_LEFT, cursor, nk_true);
if (nk_input_is_mouse_hovering_rect(in, r))
*state = NK_WIDGET_STATE_HOVERED;
if (in && left_mouse_down && left_mouse_click_in_cursor) {
if (left_mouse_down && left_mouse_click_in_cursor) {
float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w;
value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max);
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f;
*state |= NK_WIDGET_STATE_ACTIVE;
}
}
/* set progressbar widget state */
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, r))
*state |= NK_WIDGET_STATE_LEFT;
return value;
}
NK_LIB void
nk_draw_progress(struct nk_command_buffer *out, nk_flags state,
const struct nk_style_progress *style, const struct nk_rect *bounds,
const struct nk_rect *scursor, nk_size value, nk_size max)
{
const struct nk_style_item *background;
const struct nk_style_item *cursor;
NK_UNUSED(max);
NK_UNUSED(value);
/* select correct colors/images to draw */
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
cursor = &style->cursor_active;
} else if (state & NK_WIDGET_STATE_HOVER){
background = &style->hover;
cursor = &style->cursor_hover;
} else {
background = &style->normal;
cursor = &style->cursor_normal;
}
/* draw background */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
} else nk_draw_image(out, *bounds, &background->data.image, nk_white);
/* draw cursor */
if (cursor->type == NK_STYLE_ITEM_COLOR) {
nk_fill_rect(out, *scursor, style->rounding, cursor->data.color);
nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color);
} else nk_draw_image(out, *scursor, &cursor->data.image, nk_white);
}
NK_LIB nk_size
nk_do_progress(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
nk_size value, nk_size max, int modifiable,
const struct nk_style_progress *style, struct nk_input *in)
{
float prog_scale;
nk_size prog_value;
struct nk_rect cursor;
NK_ASSERT(style);
NK_ASSERT(out);
if (!out || !style) return 0;
/* calculate progressbar cursor */
cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);
cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);
cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));
prog_scale = (float)value / (float)max;
/* update progressbar */
prog_value = NK_MIN(value, max);
prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable);
cursor.w = cursor.w * prog_scale;
/* draw progressbar */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);
if (style->draw_end) style->draw_end(out, style->userdata);
return prog_value;
}
NK_API int
nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_style *style;
struct nk_input *in;
struct nk_rect bounds;
enum nk_widget_layout_states state;
nk_size old_value;
NK_ASSERT(ctx);
NK_ASSERT(cur);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !cur)
return 0;
win = ctx->current;
style = &ctx->style;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
old_value = *cur;
*cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,
*cur, max, is_modifyable, &style->progress, in);
return (*cur != old_value);
}
NK_API nk_size
nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable)
{
nk_progress(ctx, &cur, max, modifyable);
return cur;
}

495
src/nuklear_property.c Normal file
View File

@ -0,0 +1,495 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PROPERTY
*
* ===============================================================*/
NK_LIB void
nk_drag_behavior(nk_flags *state, const struct nk_input *in,
struct nk_rect drag, struct nk_property_variant *variant,
float inc_per_pixel)
{
int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
int left_mouse_click_in_cursor = in &&
nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);
nk_widget_state_reset(state);
if (nk_input_is_mouse_hovering_rect(in, drag))
*state = NK_WIDGET_STATE_HOVERED;
if (left_mouse_down && left_mouse_click_in_cursor) {
float delta, pixels;
pixels = in->mouse.delta.x;
delta = pixels * inc_per_pixel;
switch (variant->kind) {
default: break;
case NK_PROPERTY_INT:
variant->value.i = variant->value.i + (int)delta;
variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
break;
case NK_PROPERTY_FLOAT:
variant->value.f = variant->value.f + (float)delta;
variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
break;
case NK_PROPERTY_DOUBLE:
variant->value.d = variant->value.d + (double)delta;
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
break;
}
*state = NK_WIDGET_STATE_ACTIVE;
}
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, drag))
*state |= NK_WIDGET_STATE_LEFT;
}
NK_LIB void
nk_property_behavior(nk_flags *ws, const struct nk_input *in,
struct nk_rect property, struct nk_rect label, struct nk_rect edit,
struct nk_rect empty, int *state, struct nk_property_variant *variant,
float inc_per_pixel)
{
if (in && *state == NK_PROPERTY_DEFAULT) {
if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))
*state = NK_PROPERTY_EDIT;
else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))
*state = NK_PROPERTY_DRAG;
else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))
*state = NK_PROPERTY_DRAG;
}
if (*state == NK_PROPERTY_DRAG) {
nk_drag_behavior(ws, in, property, variant, inc_per_pixel);
if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;
}
}
NK_LIB void
nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,
const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,
const char *name, int len, const struct nk_user_font *font)
{
struct nk_text text;
const struct nk_style_item *background;
/* select correct background and text color */
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
text.text = style->label_active;
} else if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
text.text = style->label_hover;
} else {
background = &style->normal;
text.text = style->label_normal;
}
/* draw background */
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
text.background = nk_rgba(0,0,0,0);
} else {
text.background = background->data.color;
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color);
}
/* draw label */
text.padding = nk_vec2(0,0);
nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
}
NK_LIB void
nk_do_property(nk_flags *ws,
struct nk_command_buffer *out, struct nk_rect property,
const char *name, struct nk_property_variant *variant,
float inc_per_pixel, char *buffer, int *len,
int *state, int *cursor, int *select_begin, int *select_end,
const struct nk_style_property *style,
enum nk_property_filter filter, struct nk_input *in,
const struct nk_user_font *font, struct nk_text_edit *text_edit,
enum nk_button_behavior behavior)
{
const nk_plugin_filter filters[] = {
nk_filter_decimal,
nk_filter_float
};
int active, old;
int num_len, name_len;
char string[NK_MAX_NUMBER_BUFFER];
float size;
char *dst = 0;
int *length;
struct nk_rect left;
struct nk_rect right;
struct nk_rect label;
struct nk_rect edit;
struct nk_rect empty;
/* left decrement button */
left.h = font->height/2;
left.w = left.h;
left.x = property.x + style->border + style->padding.x;
left.y = property.y + style->border + property.h/2.0f - left.h/2;
/* text label */
name_len = nk_strlen(name);
size = font->width(font->userdata, font->height, name, name_len);
label.x = left.x + left.w + style->padding.x;
label.w = (float)size + 2 * style->padding.x;
label.y = property.y + style->border + style->padding.y;
label.h = property.h - (2 * style->border + 2 * style->padding.y);
/* right increment button */
right.y = left.y;
right.w = left.w;
right.h = left.h;
right.x = property.x + property.w - (right.w + style->padding.x);
/* edit */
if (*state == NK_PROPERTY_EDIT) {
size = font->width(font->userdata, font->height, buffer, *len);
size += style->edit.cursor_size;
length = len;
dst = buffer;
} else {
switch (variant->kind) {
default: break;
case NK_PROPERTY_INT:
nk_itoa(string, variant->value.i);
num_len = nk_strlen(string);
break;
case NK_PROPERTY_FLOAT:
NK_DTOA(string, (double)variant->value.f);
num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
break;
case NK_PROPERTY_DOUBLE:
NK_DTOA(string, variant->value.d);
num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
break;
}
size = font->width(font->userdata, font->height, string, num_len);
dst = string;
length = &num_len;
}
edit.w = (float)size + 2 * style->padding.x;
edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));
edit.x = right.x - (edit.w + style->padding.x);
edit.y = property.y + style->border;
edit.h = property.h - (2 * style->border);
/* empty left space activator */
empty.w = edit.x - (label.x + label.w);
empty.x = label.x + label.w;
empty.y = property.y;
empty.h = property.h;
/* update property */
old = (*state == NK_PROPERTY_EDIT);
nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);
/* draw property */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);
if (style->draw_end) style->draw_end(out, style->userdata);
/* execute right button */
if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {
switch (variant->kind) {
default: break;
case NK_PROPERTY_INT:
variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;
case NK_PROPERTY_FLOAT:
variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;
case NK_PROPERTY_DOUBLE:
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;
}
}
/* execute left button */
if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {
switch (variant->kind) {
default: break;
case NK_PROPERTY_INT:
variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;
case NK_PROPERTY_FLOAT:
variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;
case NK_PROPERTY_DOUBLE:
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;
}
}
if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) {
/* property has been activated so setup buffer */
NK_MEMCPY(buffer, dst, (nk_size)*length);
*cursor = nk_utf_len(buffer, *length);
*len = *length;
length = len;
dst = buffer;
active = 0;
} else active = (*state == NK_PROPERTY_EDIT);
/* execute and run text edit field */
nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);
text_edit->active = (unsigned char)active;
text_edit->string.len = *length;
text_edit->cursor = NK_CLAMP(0, *cursor, *length);
text_edit->select_start = NK_CLAMP(0,*select_begin, *length);
text_edit->select_end = NK_CLAMP(0,*select_end, *length);
text_edit->string.buffer.allocated = (nk_size)*length;
text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;
text_edit->string.buffer.memory.ptr = dst;
text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;
text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;
nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT,
filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);
*length = text_edit->string.len;
*cursor = text_edit->cursor;
*select_begin = text_edit->select_start;
*select_end = text_edit->select_end;
if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))
text_edit->active = nk_false;
if (active && !text_edit->active) {
/* property is now not active so convert edit text to value*/
*state = NK_PROPERTY_DEFAULT;
buffer[*len] = '\0';
switch (variant->kind) {
default: break;
case NK_PROPERTY_INT:
variant->value.i = nk_strtoi(buffer, 0);
variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
break;
case NK_PROPERTY_FLOAT:
nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
variant->value.f = nk_strtof(buffer, 0);
variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
break;
case NK_PROPERTY_DOUBLE:
nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
variant->value.d = nk_strtod(buffer, 0);
variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
break;
}
}
}
NK_LIB struct nk_property_variant
nk_property_variant_int(int value, int min_value, int max_value, int step)
{
struct nk_property_variant result;
result.kind = NK_PROPERTY_INT;
result.value.i = value;
result.min_value.i = min_value;
result.max_value.i = max_value;
result.step.i = step;
return result;
}
NK_LIB struct nk_property_variant
nk_property_variant_float(float value, float min_value, float max_value, float step)
{
struct nk_property_variant result;
result.kind = NK_PROPERTY_FLOAT;
result.value.f = value;
result.min_value.f = min_value;
result.max_value.f = max_value;
result.step.f = step;
return result;
}
NK_LIB struct nk_property_variant
nk_property_variant_double(double value, double min_value, double max_value,
double step)
{
struct nk_property_variant result;
result.kind = NK_PROPERTY_DOUBLE;
result.value.d = value;
result.min_value.d = min_value;
result.max_value.d = max_value;
result.step.d = step;
return result;
}
NK_LIB void
nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,
float inc_per_pixel, const enum nk_property_filter filter)
{
struct nk_window *win;
struct nk_panel *layout;
struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states s;
int *state = 0;
nk_hash hash = 0;
char *buffer = 0;
int *len = 0;
int *cursor = 0;
int *select_begin = 0;
int *select_end = 0;
int old_state;
char dummy_buffer[NK_MAX_NUMBER_BUFFER];
int dummy_state = NK_PROPERTY_DEFAULT;
int dummy_length = 0;
int dummy_cursor = 0;
int dummy_select_begin = 0;
int dummy_select_end = 0;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
style = &ctx->style;
s = nk_widget(&bounds, ctx);
if (!s) return;
/* calculate hash from name */
if (name[0] == '#') {
hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);
name++; /* special number hash */
} else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);
/* check if property is currently hot item */
if (win->property.active && hash == win->property.name) {
buffer = win->property.buffer;
len = &win->property.length;
cursor = &win->property.cursor;
state = &win->property.state;
select_begin = &win->property.select_start;
select_end = &win->property.select_end;
} else {
buffer = dummy_buffer;
len = &dummy_length;
cursor = &dummy_cursor;
state = &dummy_state;
select_begin = &dummy_select_begin;
select_end = &dummy_select_end;
}
/* execute property widget */
old_state = *state;
ctx->text_edit.clip = ctx->clip;
in = ((s == NK_WIDGET_ROM && !win->property.active) ||
layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,
variant, inc_per_pixel, buffer, len, state, cursor, select_begin,
select_end, &style->property, filter, in, style->font, &ctx->text_edit,
ctx->button_behavior);
if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) {
/* current property is now hot */
win->property.active = 1;
NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);
win->property.length = *len;
win->property.cursor = *cursor;
win->property.state = *state;
win->property.name = hash;
win->property.select_start = *select_begin;
win->property.select_end = *select_end;
if (*state == NK_PROPERTY_DRAG) {
ctx->input.mouse.grab = nk_true;
ctx->input.mouse.grabbed = nk_true;
}
}
/* check if previously active property is now inactive */
if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {
if (old_state == NK_PROPERTY_DRAG) {
ctx->input.mouse.grab = nk_false;
ctx->input.mouse.grabbed = nk_false;
ctx->input.mouse.ungrab = nk_true;
}
win->property.select_start = 0;
win->property.select_end = 0;
win->property.active = 0;
}
}
NK_API void
nk_property_int(struct nk_context *ctx, const char *name,
int min, int *val, int max, int step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
NK_ASSERT(val);
if (!ctx || !ctx->current || !name || !val) return;
variant = nk_property_variant_int(*val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
*val = variant.value.i;
}
NK_API void
nk_property_float(struct nk_context *ctx, const char *name,
float min, float *val, float max, float step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
NK_ASSERT(val);
if (!ctx || !ctx->current || !name || !val) return;
variant = nk_property_variant_float(*val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
*val = variant.value.f;
}
NK_API void
nk_property_double(struct nk_context *ctx, const char *name,
double min, double *val, double max, double step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
NK_ASSERT(val);
if (!ctx || !ctx->current || !name || !val) return;
variant = nk_property_variant_double(*val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
*val = variant.value.d;
}
NK_API int
nk_propertyi(struct nk_context *ctx, const char *name, int min, int val,
int max, int step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
if (!ctx || !ctx->current || !name) return val;
variant = nk_property_variant_int(val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
val = variant.value.i;
return val;
}
NK_API float
nk_propertyf(struct nk_context *ctx, const char *name, float min,
float val, float max, float step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
if (!ctx || !ctx->current || !name) return val;
variant = nk_property_variant_float(val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
val = variant.value.f;
return val;
}
NK_API double
nk_propertyd(struct nk_context *ctx, const char *name, double min,
double val, double max, double step, float inc_per_pixel)
{
struct nk_property_variant variant;
NK_ASSERT(ctx);
NK_ASSERT(name);
if (!ctx || !ctx->current || !name) return val;
variant = nk_property_variant_double(val, min, max, step);
nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
val = variant.value.d;
return val;
}

294
src/nuklear_scrollbar.c Normal file
View File

@ -0,0 +1,294 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SCROLLBAR
*
* ===============================================================*/
NK_LIB float
nk_scrollbar_behavior(nk_flags *state, struct nk_input *in,
int has_scrolling, const struct nk_rect *scroll,
const struct nk_rect *cursor, const struct nk_rect *empty0,
const struct nk_rect *empty1, float scroll_offset,
float target, float scroll_step, enum nk_orientation o)
{
nk_flags ws = 0;
int left_mouse_down;
int left_mouse_click_in_cursor;
float scroll_delta;
nk_widget_state_reset(state);
if (!in) return scroll_offset;
left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
NK_BUTTON_LEFT, *cursor, nk_true);
if (nk_input_is_mouse_hovering_rect(in, *scroll))
*state = NK_WIDGET_STATE_HOVERED;
scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;
if (left_mouse_down && left_mouse_click_in_cursor) {
/* update cursor by mouse dragging */
float pixel, delta;
*state = NK_WIDGET_STATE_ACTIVE;
if (o == NK_VERTICAL) {
float cursor_y;
pixel = in->mouse.delta.y;
delta = (pixel / scroll->h) * target;
scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);
cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;
} else {
float cursor_x;
pixel = in->mouse.delta.x;
delta = (pixel / scroll->w) * target;
scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);
cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;
}
} else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||
nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {
/* scroll page up by click on empty space or shortcut */
if (o == NK_VERTICAL)
scroll_offset = NK_MAX(0, scroll_offset - scroll->h);
else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);
} else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||
nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {
/* scroll page down by click on empty space or shortcut */
if (o == NK_VERTICAL)
scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);
else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);
} else if (has_scrolling) {
if ((scroll_delta < 0 || (scroll_delta > 0))) {
/* update cursor by mouse scrolling */
scroll_offset = scroll_offset + scroll_step * (-scroll_delta);
if (o == NK_VERTICAL)
scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);
else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);
} else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {
/* update cursor to the beginning */
if (o == NK_VERTICAL) scroll_offset = 0;
} else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {
/* update cursor to the end */
if (o == NK_VERTICAL) scroll_offset = target - scroll->h;
}
}
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))
*state |= NK_WIDGET_STATE_LEFT;
return scroll_offset;
}
NK_LIB void
nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,
const struct nk_style_scrollbar *style, const struct nk_rect *bounds,
const struct nk_rect *scroll)
{
const struct nk_style_item *background;
const struct nk_style_item *cursor;
/* select correct colors/images to draw */
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
cursor = &style->cursor_active;
} else if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
cursor = &style->cursor_hover;
} else {
background = &style->normal;
cursor = &style->cursor_normal;
}
/* draw background */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
} else {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
}
/* draw cursor */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);
nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);
} else nk_draw_image(out, *scroll, &cursor->data.image, nk_white);
}
NK_LIB float
nk_do_scrollbarv(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
float offset, float target, float step, float button_pixel_inc,
const struct nk_style_scrollbar *style, struct nk_input *in,
const struct nk_user_font *font)
{
struct nk_rect empty_north;
struct nk_rect empty_south;
struct nk_rect cursor;
float scroll_step;
float scroll_offset;
float scroll_off;
float scroll_ratio;
NK_ASSERT(out);
NK_ASSERT(style);
NK_ASSERT(state);
if (!out || !style) return 0;
scroll.w = NK_MAX(scroll.w, 1);
scroll.h = NK_MAX(scroll.h, 0);
if (target <= scroll.h) return 0;
/* optional scrollbar buttons */
if (style->show_buttons) {
nk_flags ws;
float scroll_h;
struct nk_rect button;
button.x = scroll.x;
button.w = scroll.w;
button.h = scroll.w;
scroll_h = NK_MAX(scroll.h - 2 * button.h,0);
scroll_step = NK_MIN(step, button_pixel_inc);
/* decrement button */
button.y = scroll.y;
if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
NK_BUTTON_REPEATER, &style->dec_button, in, font))
offset = offset - scroll_step;
/* increment button */
button.y = scroll.y + scroll.h - button.h;
if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
NK_BUTTON_REPEATER, &style->inc_button, in, font))
offset = offset + scroll_step;
scroll.y = scroll.y + button.h;
scroll.h = scroll_h;
}
/* calculate scrollbar constants */
scroll_step = NK_MIN(step, scroll.h);
scroll_offset = NK_CLAMP(0, offset, target - scroll.h);
scroll_ratio = scroll.h / target;
scroll_off = scroll_offset / target;
/* calculate scrollbar cursor bounds */
cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0);
cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;
cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);
cursor.x = scroll.x + style->border + style->padding.x;
/* calculate empty space around cursor */
empty_north.x = scroll.x;
empty_north.y = scroll.y;
empty_north.w = scroll.w;
empty_north.h = NK_MAX(cursor.y - scroll.y, 0);
empty_south.x = scroll.x;
empty_south.y = cursor.y + cursor.h;
empty_south.w = scroll.w;
empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0);
/* update scrollbar */
scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
&empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);
scroll_off = scroll_offset / target;
cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;
/* draw scrollbar */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
if (style->draw_end) style->draw_end(out, style->userdata);
return scroll_offset;
}
NK_LIB float
nk_do_scrollbarh(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
float offset, float target, float step, float button_pixel_inc,
const struct nk_style_scrollbar *style, struct nk_input *in,
const struct nk_user_font *font)
{
struct nk_rect cursor;
struct nk_rect empty_west;
struct nk_rect empty_east;
float scroll_step;
float scroll_offset;
float scroll_off;
float scroll_ratio;
NK_ASSERT(out);
NK_ASSERT(style);
if (!out || !style) return 0;
/* scrollbar background */
scroll.h = NK_MAX(scroll.h, 1);
scroll.w = NK_MAX(scroll.w, 2 * scroll.h);
if (target <= scroll.w) return 0;
/* optional scrollbar buttons */
if (style->show_buttons) {
nk_flags ws;
float scroll_w;
struct nk_rect button;
button.y = scroll.y;
button.w = scroll.h;
button.h = scroll.h;
scroll_w = scroll.w - 2 * button.w;
scroll_step = NK_MIN(step, button_pixel_inc);
/* decrement button */
button.x = scroll.x;
if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
NK_BUTTON_REPEATER, &style->dec_button, in, font))
offset = offset - scroll_step;
/* increment button */
button.x = scroll.x + scroll.w - button.w;
if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
NK_BUTTON_REPEATER, &style->inc_button, in, font))
offset = offset + scroll_step;
scroll.x = scroll.x + button.w;
scroll.w = scroll_w;
}
/* calculate scrollbar constants */
scroll_step = NK_MIN(step, scroll.w);
scroll_offset = NK_CLAMP(0, offset, target - scroll.w);
scroll_ratio = scroll.w / target;
scroll_off = scroll_offset / target;
/* calculate cursor bounds */
cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);
cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;
cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);
cursor.y = scroll.y + style->border + style->padding.y;
/* calculate empty space around cursor */
empty_west.x = scroll.x;
empty_west.y = scroll.y;
empty_west.w = cursor.x - scroll.x;
empty_west.h = scroll.h;
empty_east.x = cursor.x + cursor.w;
empty_east.y = scroll.y;
empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);
empty_east.h = scroll.h;
/* update scrollbar */
scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
&empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);
scroll_off = scroll_offset / target;
cursor.x = scroll.x + (scroll_off * scroll.w);
/* draw scrollbar */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
if (style->draw_end) style->draw_end(out, style->userdata);
return scroll_offset;
}

223
src/nuklear_selectable.c Normal file
View File

@ -0,0 +1,223 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SELECTABLE
*
* ===============================================================*/
NK_LIB void
nk_draw_selectable(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_selectable *style, int active,
const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img,
const char *string, int len, nk_flags align, const struct nk_user_font *font)
{
const struct nk_style_item *background;
struct nk_text text;
text.padding = style->padding;
/* select correct colors/images */
if (!active) {
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->pressed;
text.text = style->text_pressed;
} else if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
text.text = style->text_hover;
} else {
background = &style->normal;
text.text = style->text_normal;
}
} else {
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->pressed_active;
text.text = style->text_pressed_active;
} else if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover_active;
text.text = style->text_hover_active;
} else {
background = &style->normal_active;
text.text = style->text_normal_active;
}
}
/* draw selectable background and text */
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
text.background = nk_rgba(0,0,0,0);
} else {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
text.background = background->data.color;
}
if (img && icon) nk_draw_image(out, *icon, img, nk_white);
nk_widget_text(out, *bounds, string, len, &text, align, font);
}
NK_LIB int
nk_do_selectable(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
const struct nk_style_selectable *style, const struct nk_input *in,
const struct nk_user_font *font)
{
int old_value;
struct nk_rect touch;
NK_ASSERT(state);
NK_ASSERT(out);
NK_ASSERT(str);
NK_ASSERT(len);
NK_ASSERT(value);
NK_ASSERT(style);
NK_ASSERT(font);
if (!state || !out || !str || !len || !value || !style || !font) return 0;
old_value = *value;
/* remove padding */
touch.x = bounds.x - style->touch_padding.x;
touch.y = bounds.y - style->touch_padding.y;
touch.w = bounds.w + style->touch_padding.x * 2;
touch.h = bounds.h + style->touch_padding.y * 2;
/* update button */
if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
*value = !(*value);
/* draw selectable */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return old_value != *value;
}
NK_LIB int
nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
const struct nk_image *img, const struct nk_style_selectable *style,
const struct nk_input *in, const struct nk_user_font *font)
{
int old_value;
struct nk_rect touch;
struct nk_rect icon;
NK_ASSERT(state);
NK_ASSERT(out);
NK_ASSERT(str);
NK_ASSERT(len);
NK_ASSERT(value);
NK_ASSERT(style);
NK_ASSERT(font);
if (!state || !out || !str || !len || !value || !style || !font) return 0;
old_value = *value;
/* toggle behavior */
touch.x = bounds.x - style->touch_padding.x;
touch.y = bounds.y - style->touch_padding.y;
touch.w = bounds.w + style->touch_padding.x * 2;
touch.h = bounds.h + style->touch_padding.y * 2;
if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
*value = !(*value);
icon.y = bounds.y + style->padding.y;
icon.w = icon.h = bounds.h - 2 * style->padding.y;
if (align & NK_TEXT_ALIGN_LEFT) {
icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
icon.x = NK_MAX(icon.x, 0);
} else icon.x = bounds.x + 2 * style->padding.x;
icon.x += style->image_padding.x;
icon.y += style->image_padding.y;
icon.w -= 2 * style->image_padding.x;
icon.h -= 2 * style->image_padding.y;
/* draw selectable */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return old_value != *value;
}
NK_API int
nk_selectable_text(struct nk_context *ctx, const char *str, int len,
nk_flags align, int *value)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
const struct nk_style *style;
enum nk_widget_layout_states state;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(value);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !value)
return 0;
win = ctx->current;
layout = win->layout;
style = &ctx->style;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,
str, len, align, value, &style->selectable, in, style->font);
}
NK_API int
nk_selectable_image_text(struct nk_context *ctx, struct nk_image img,
const char *str, int len, nk_flags align, int *value)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
const struct nk_style *style;
enum nk_widget_layout_states state;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(value);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !value)
return 0;
win = ctx->current;
layout = win->layout;
style = &ctx->style;
state = nk_widget(&bounds, ctx);
if (!state) return 0;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,
str, len, align, value, &img, &style->selectable, in, style->font);
}
NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len,
nk_flags align, int value)
{
nk_selectable_text(ctx, str, len, align, &value);return value;
}
NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value)
{
return nk_selectable_text(ctx, str, nk_strlen(str), align, value);
}
NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,
const char *str, nk_flags align, int *value)
{
return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);
}
NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value)
{
nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;
}
NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img,
const char *str, nk_flags align, int value)
{
nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;
}
NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img,
const char *str, int len, nk_flags align, int value)
{
nk_selectable_image_text(ctx, img, str, len, align, &value);return value;
}

254
src/nuklear_slider.c Normal file
View File

@ -0,0 +1,254 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SLIDER
*
* ===============================================================*/
NK_LIB float
nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,
struct nk_rect *visual_cursor, struct nk_input *in,
struct nk_rect bounds, float slider_min, float slider_max, float slider_value,
float slider_step, float slider_steps)
{
int left_mouse_down;
int left_mouse_click_in_cursor;
/* check if visual cursor is being dragged */
nk_widget_state_reset(state);
left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
NK_BUTTON_LEFT, *visual_cursor, nk_true);
if (left_mouse_down && left_mouse_click_in_cursor) {
float ratio = 0;
const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);
const float pxstep = bounds.w / slider_steps;
/* only update value if the next slider step is reached */
*state = NK_WIDGET_STATE_ACTIVE;
if (NK_ABS(d) >= pxstep) {
const float steps = (float)((int)(NK_ABS(d) / pxstep));
slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);
slider_value = NK_CLAMP(slider_min, slider_value, slider_max);
ratio = (slider_value - slider_min)/slider_step;
logical_cursor->x = bounds.x + (logical_cursor->w * ratio);
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;
}
}
/* slider widget state */
if (nk_input_is_mouse_hovering_rect(in, bounds))
*state = NK_WIDGET_STATE_HOVERED;
if (*state & NK_WIDGET_STATE_HOVER &&
!nk_input_is_mouse_prev_hovering_rect(in, bounds))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
*state |= NK_WIDGET_STATE_LEFT;
return slider_value;
}
NK_LIB void
nk_draw_slider(struct nk_command_buffer *out, nk_flags state,
const struct nk_style_slider *style, const struct nk_rect *bounds,
const struct nk_rect *visual_cursor, float min, float value, float max)
{
struct nk_rect fill;
struct nk_rect bar;
const struct nk_style_item *background;
/* select correct slider images/colors */
struct nk_color bar_color;
const struct nk_style_item *cursor;
NK_UNUSED(min);
NK_UNUSED(max);
NK_UNUSED(value);
if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->active;
bar_color = style->bar_active;
cursor = &style->cursor_active;
} else if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
bar_color = style->bar_hover;
cursor = &style->cursor_hover;
} else {
background = &style->normal;
bar_color = style->bar_normal;
cursor = &style->cursor_normal;
}
/* calculate slider background bar */
bar.x = bounds->x;
bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;
bar.w = bounds->w;
bar.h = bounds->h/6;
/* filled background bar style */
fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;
fill.x = bar.x;
fill.y = bar.y;
fill.h = bar.h;
/* draw background */
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, *bounds, &background->data.image, nk_white);
} else {
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
}
/* draw slider bar */
nk_fill_rect(out, bar, style->rounding, bar_color);
nk_fill_rect(out, fill, style->rounding, style->bar_filled);
/* draw cursor */
if (cursor->type == NK_STYLE_ITEM_IMAGE)
nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white);
else nk_fill_circle(out, *visual_cursor, cursor->data.color);
}
NK_LIB float
nk_do_slider(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
float min, float val, float max, float step,
const struct nk_style_slider *style, struct nk_input *in,
const struct nk_user_font *font)
{
float slider_range;
float slider_min;
float slider_max;
float slider_value;
float slider_steps;
float cursor_offset;
struct nk_rect visual_cursor;
struct nk_rect logical_cursor;
NK_ASSERT(style);
NK_ASSERT(out);
if (!out || !style)
return 0;
/* remove padding from slider bounds */
bounds.x = bounds.x + style->padding.x;
bounds.y = bounds.y + style->padding.y;
bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);
bounds.w -= 2 * style->padding.x;
bounds.h -= 2 * style->padding.y;
/* optional buttons */
if (style->show_buttons) {
nk_flags ws;
struct nk_rect button;
button.y = bounds.y;
button.w = bounds.h;
button.h = bounds.h;
/* decrement button */
button.x = bounds.x;
if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,
&style->dec_button, in, font))
val -= step;
/* increment button */
button.x = (bounds.x + bounds.w) - button.w;
if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,
&style->inc_button, in, font))
val += step;
bounds.x = bounds.x + button.w + style->spacing.x;
bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);
}
/* remove one cursor size to support visual cursor */
bounds.x += style->cursor_size.x*0.5f;
bounds.w -= style->cursor_size.x;
/* make sure the provided values are correct */
slider_max = NK_MAX(min, max);
slider_min = NK_MIN(min, max);
slider_value = NK_CLAMP(slider_min, val, slider_max);
slider_range = slider_max - slider_min;
slider_steps = slider_range / step;
cursor_offset = (slider_value - slider_min) / step;
/* calculate cursor
Basically you have two cursors. One for visual representation and interaction
and one for updating the actual cursor value. */
logical_cursor.h = bounds.h;
logical_cursor.w = bounds.w / slider_steps;
logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);
logical_cursor.y = bounds.y;
visual_cursor.h = style->cursor_size.y;
visual_cursor.w = style->cursor_size.x;
visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;
visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,
in, bounds, slider_min, slider_max, slider_value, step, slider_steps);
visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
/* draw slider */
if (style->draw_begin) style->draw_begin(out, style->userdata);
nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);
if (style->draw_end) style->draw_end(out, style->userdata);
return slider_value;
}
NK_API int
nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,
float value_step)
{
struct nk_window *win;
struct nk_panel *layout;
struct nk_input *in;
const struct nk_style *style;
int ret = 0;
float old_value;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
NK_ASSERT(value);
if (!ctx || !ctx->current || !ctx->current->layout || !value)
return ret;
win = ctx->current;
style = &ctx->style;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return ret;
in = (/*state == NK_WIDGET_ROM || */ layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
old_value = *value;
*value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,
old_value, max_value, value_step, &style->slider, in, style->font);
return (old_value > *value || old_value < *value);
}
NK_API float
nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)
{
nk_slider_float(ctx, min, &val, max, step); return val;
}
NK_API int
nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)
{
float value = (float)val;
nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
return (int)value;
}
NK_API int
nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)
{
int ret;
float value = (float)*val;
ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
*val = (int)value;
return ret;
}

451
src/nuklear_string.c Normal file
View File

@ -0,0 +1,451 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* STRING
*
* ===============================================================*/
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_API void
nk_str_init_default(struct nk_str *str)
{
struct nk_allocator alloc;
alloc.userdata.ptr = 0;
alloc.alloc = nk_malloc;
alloc.free = nk_mfree;
nk_buffer_init(&str->buffer, &alloc, 32);
str->len = 0;
}
#endif
NK_API void
nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)
{
nk_buffer_init(&str->buffer, alloc, size);
str->len = 0;
}
NK_API void
nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)
{
nk_buffer_init_fixed(&str->buffer, memory, size);
str->len = 0;
}
NK_API int
nk_str_append_text_char(struct nk_str *s, const char *str, int len)
{
char *mem;
NK_ASSERT(s);
NK_ASSERT(str);
if (!s || !str || !len) return 0;
mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
if (!mem) return 0;
NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
s->len += nk_utf_len(str, len);
return len;
}
NK_API int
nk_str_append_str_char(struct nk_str *s, const char *str)
{
return nk_str_append_text_char(s, str, nk_strlen(str));
}
NK_API int
nk_str_append_text_utf8(struct nk_str *str, const char *text, int len)
{
int i = 0;
int byte_len = 0;
nk_rune unicode;
if (!str || !text || !len) return 0;
for (i = 0; i < len; ++i)
byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
nk_str_append_text_char(str, text, byte_len);
return len;
}
NK_API int
nk_str_append_str_utf8(struct nk_str *str, const char *text)
{
int runes = 0;
int byte_len = 0;
int num_runes = 0;
int glyph_len = 0;
nk_rune unicode;
if (!str || !text) return 0;
glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
while (unicode != '\0' && glyph_len) {
glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
byte_len += glyph_len;
num_runes++;
}
nk_str_append_text_char(str, text, byte_len);
return runes;
}
NK_API int
nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)
{
int i = 0;
int byte_len = 0;
nk_glyph glyph;
NK_ASSERT(str);
if (!str || !text || !len) return 0;
for (i = 0; i < len; ++i) {
byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);
if (!byte_len) break;
nk_str_append_text_char(str, glyph, byte_len);
}
return len;
}
NK_API int
nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)
{
int i = 0;
nk_glyph glyph;
int byte_len;
NK_ASSERT(str);
if (!str || !runes) return 0;
while (runes[i] != '\0') {
byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
nk_str_append_text_char(str, glyph, byte_len);
i++;
}
return i;
}
NK_API int
nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)
{
int i;
void *mem;
char *src;
char *dst;
int copylen;
NK_ASSERT(s);
NK_ASSERT(str);
NK_ASSERT(len >= 0);
if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;
if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&
(s->buffer.type == NK_BUFFER_FIXED)) return 0;
copylen = (int)s->buffer.allocated - pos;
if (!copylen) {
nk_str_append_text_char(s, str, len);
return 1;
}
mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
if (!mem) return 0;
/* memmove */
NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);
NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);
dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));
src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));
for (i = 0; i < copylen; ++i) *dst-- = *src--;
mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);
NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
return 1;
}
NK_API int
nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)
{
int glyph_len;
nk_rune unicode;
const char *begin;
const char *buffer;
NK_ASSERT(str);
NK_ASSERT(cstr);
NK_ASSERT(len);
if (!str || !cstr || !len) return 0;
begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);
if (!str->len)
return nk_str_append_text_char(str, cstr, len);
buffer = nk_str_get_const(str);
if (!begin) return 0;
return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);
}
NK_API int
nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)
{
return nk_str_insert_text_utf8(str, pos, text, len);
}
NK_API int
nk_str_insert_str_char(struct nk_str *str, int pos, const char *text)
{
return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));
}
NK_API int
nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
{
int i = 0;
int byte_len = 0;
nk_rune unicode;
NK_ASSERT(str);
NK_ASSERT(text);
if (!str || !text || !len) return 0;
for (i = 0; i < len; ++i)
byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
nk_str_insert_at_rune(str, pos, text, byte_len);
return len;
}
NK_API int
nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
{
int runes = 0;
int byte_len = 0;
int num_runes = 0;
int glyph_len = 0;
nk_rune unicode;
if (!str || !text) return 0;
glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
while (unicode != '\0' && glyph_len) {
glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
byte_len += glyph_len;
num_runes++;
}
nk_str_insert_at_rune(str, pos, text, byte_len);
return runes;
}
NK_API int
nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)
{
int i = 0;
int byte_len = 0;
nk_glyph glyph;
NK_ASSERT(str);
if (!str || !runes || !len) return 0;
for (i = 0; i < len; ++i) {
byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
if (!byte_len) break;
nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
}
return len;
}
NK_API int
nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)
{
int i = 0;
nk_glyph glyph;
int byte_len;
NK_ASSERT(str);
if (!str || !runes) return 0;
while (runes[i] != '\0') {
byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
i++;
}
return i;
}
NK_API void
nk_str_remove_chars(struct nk_str *s, int len)
{
NK_ASSERT(s);
NK_ASSERT(len >= 0);
if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;
NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
s->buffer.allocated -= (nk_size)len;
s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
}
NK_API void
nk_str_remove_runes(struct nk_str *str, int len)
{
int index;
const char *begin;
const char *end;
nk_rune unicode;
NK_ASSERT(str);
NK_ASSERT(len >= 0);
if (!str || len < 0) return;
if (len >= str->len) {
str->len = 0;
return;
}
index = str->len - len;
begin = nk_str_at_rune(str, index, &unicode, &len);
end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;
nk_str_remove_chars(str, (int)(end-begin)+1);
}
NK_API void
nk_str_delete_chars(struct nk_str *s, int pos, int len)
{
NK_ASSERT(s);
if (!s || !len || (nk_size)pos > s->buffer.allocated ||
(nk_size)(pos + len) > s->buffer.allocated) return;
if ((nk_size)(pos + len) < s->buffer.allocated) {
/* memmove */
char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);
char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);
NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));
NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
s->buffer.allocated -= (nk_size)len;
} else nk_str_remove_chars(s, len);
s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
}
NK_API void
nk_str_delete_runes(struct nk_str *s, int pos, int len)
{
char *temp;
nk_rune unicode;
char *begin;
char *end;
int unused;
NK_ASSERT(s);
NK_ASSERT(s->len >= pos + len);
if (s->len < pos + len)
len = NK_CLAMP(0, (s->len - pos), s->len);
if (!len) return;
temp = (char *)s->buffer.memory.ptr;
begin = nk_str_at_rune(s, pos, &unicode, &unused);
if (!begin) return;
s->buffer.memory.ptr = begin;
end = nk_str_at_rune(s, len, &unicode, &unused);
s->buffer.memory.ptr = temp;
if (!end) return;
nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));
}
NK_API char*
nk_str_at_char(struct nk_str *s, int pos)
{
NK_ASSERT(s);
if (!s || pos > (int)s->buffer.allocated) return 0;
return nk_ptr_add(char, s->buffer.memory.ptr, pos);
}
NK_API char*
nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)
{
int i = 0;
int src_len = 0;
int glyph_len = 0;
char *text;
int text_len;
NK_ASSERT(str);
NK_ASSERT(unicode);
NK_ASSERT(len);
if (!str || !unicode || !len) return 0;
if (pos < 0) {
*unicode = 0;
*len = 0;
return 0;
}
text = (char*)str->buffer.memory.ptr;
text_len = (int)str->buffer.allocated;
glyph_len = nk_utf_decode(text, unicode, text_len);
while (glyph_len) {
if (i == pos) {
*len = glyph_len;
break;
}
i++;
src_len = src_len + glyph_len;
glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
}
if (i != pos) return 0;
return text + src_len;
}
NK_API const char*
nk_str_at_char_const(const struct nk_str *s, int pos)
{
NK_ASSERT(s);
if (!s || pos > (int)s->buffer.allocated) return 0;
return nk_ptr_add(char, s->buffer.memory.ptr, pos);
}
NK_API const char*
nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)
{
int i = 0;
int src_len = 0;
int glyph_len = 0;
char *text;
int text_len;
NK_ASSERT(str);
NK_ASSERT(unicode);
NK_ASSERT(len);
if (!str || !unicode || !len) return 0;
if (pos < 0) {
*unicode = 0;
*len = 0;
return 0;
}
text = (char*)str->buffer.memory.ptr;
text_len = (int)str->buffer.allocated;
glyph_len = nk_utf_decode(text, unicode, text_len);
while (glyph_len) {
if (i == pos) {
*len = glyph_len;
break;
}
i++;
src_len = src_len + glyph_len;
glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
}
if (i != pos) return 0;
return text + src_len;
}
NK_API nk_rune
nk_str_rune_at(const struct nk_str *str, int pos)
{
int len;
nk_rune unicode = 0;
nk_str_at_const(str, pos, &unicode, &len);
return unicode;
}
NK_API char*
nk_str_get(struct nk_str *s)
{
NK_ASSERT(s);
if (!s || !s->len || !s->buffer.allocated) return 0;
return (char*)s->buffer.memory.ptr;
}
NK_API const char*
nk_str_get_const(const struct nk_str *s)
{
NK_ASSERT(s);
if (!s || !s->len || !s->buffer.allocated) return 0;
return (const char*)s->buffer.memory.ptr;
}
NK_API int
nk_str_len(struct nk_str *s)
{
NK_ASSERT(s);
if (!s || !s->len || !s->buffer.allocated) return 0;
return s->len;
}
NK_API int
nk_str_len_char(struct nk_str *s)
{
NK_ASSERT(s);
if (!s || !s->len || !s->buffer.allocated) return 0;
return (int)s->buffer.allocated;
}
NK_API void
nk_str_clear(struct nk_str *str)
{
NK_ASSERT(str);
nk_buffer_clear(&str->buffer);
str->len = 0;
}
NK_API void
nk_str_free(struct nk_str *str)
{
NK_ASSERT(str);
nk_buffer_free(&str->buffer);
str->len = 0;
}

764
src/nuklear_style.c Normal file
View File

@ -0,0 +1,764 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* STYLE
*
* ===============================================================*/
NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}
#define NK_COLOR_MAP(NK_COLOR)\
NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \
NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \
NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \
NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \
NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \
NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \
NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \
NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \
NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \
NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \
NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \
NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \
NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \
NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \
NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \
NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \
NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \
NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \
NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \
NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \
NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \
NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \
NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT, 255, 0, 0, 255) \
NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \
NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \
NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER, 120,120,120,255) \
NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, 150,150,150,255) \
NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255)
NK_GLOBAL const struct nk_color
nk_default_color_style[NK_COLOR_COUNT] = {
#define NK_COLOR(a,b,c,d,e) {b,c,d,e},
NK_COLOR_MAP(NK_COLOR)
#undef NK_COLOR
};
NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {
#define NK_COLOR(a,b,c,d,e) #a,
NK_COLOR_MAP(NK_COLOR)
#undef NK_COLOR
};
NK_API const char*
nk_style_get_color_by_name(enum nk_style_colors c)
{
return nk_color_names[c];
}
NK_API struct nk_style_item
nk_style_item_image(struct nk_image img)
{
struct nk_style_item i;
i.type = NK_STYLE_ITEM_IMAGE;
i.data.image = img;
return i;
}
NK_API struct nk_style_item
nk_style_item_color(struct nk_color col)
{
struct nk_style_item i;
i.type = NK_STYLE_ITEM_COLOR;
i.data.color = col;
return i;
}
NK_API struct nk_style_item
nk_style_item_hide(void)
{
struct nk_style_item i;
i.type = NK_STYLE_ITEM_COLOR;
i.data.color = nk_rgba(0,0,0,0);
return i;
}
NK_API void
nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
{
struct nk_style *style;
struct nk_style_text *text;
struct nk_style_button *button;
struct nk_style_toggle *toggle;
struct nk_style_selectable *select;
struct nk_style_slider *slider;
struct nk_style_progress *prog;
struct nk_style_scrollbar *scroll;
struct nk_style_edit *edit;
struct nk_style_property *property;
struct nk_style_combo *combo;
struct nk_style_chart *chart;
struct nk_style_tab *tab;
struct nk_style_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
style = &ctx->style;
table = (!table) ? nk_default_color_style: table;
/* default text */
text = &style->text;
text->color = table[NK_COLOR_TEXT];
text->padding = nk_vec2(0,0);
/* default button */
button = &style->button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]);
button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
button->border_color = table[NK_COLOR_BORDER];
button->text_background = table[NK_COLOR_BUTTON];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->image_padding = nk_vec2(0.0f,0.0f);
button->touch_padding = nk_vec2(0.0f, 0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 1.0f;
button->rounding = 4.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* contextual button */
button = &style->contextual_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
button->border_color = table[NK_COLOR_WINDOW];
button->text_background = table[NK_COLOR_WINDOW];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* menu button */
button = &style->menu_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->border_color = table[NK_COLOR_WINDOW];
button->text_background = table[NK_COLOR_WINDOW];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 1.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* checkbox toggle */
toggle = &style->checkbox;
nk_zero_struct(*toggle);
toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
toggle->userdata = nk_handle_ptr(0);
toggle->text_background = table[NK_COLOR_WINDOW];
toggle->text_normal = table[NK_COLOR_TEXT];
toggle->text_hover = table[NK_COLOR_TEXT];
toggle->text_active = table[NK_COLOR_TEXT];
toggle->padding = nk_vec2(2.0f, 2.0f);
toggle->touch_padding = nk_vec2(0,0);
toggle->border_color = nk_rgba(0,0,0,0);
toggle->border = 0.0f;
toggle->spacing = 4;
/* option toggle */
toggle = &style->option;
nk_zero_struct(*toggle);
toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
toggle->userdata = nk_handle_ptr(0);
toggle->text_background = table[NK_COLOR_WINDOW];
toggle->text_normal = table[NK_COLOR_TEXT];
toggle->text_hover = table[NK_COLOR_TEXT];
toggle->text_active = table[NK_COLOR_TEXT];
toggle->padding = nk_vec2(3.0f, 3.0f);
toggle->touch_padding = nk_vec2(0,0);
toggle->border_color = nk_rgba(0,0,0,0);
toggle->border = 0.0f;
toggle->spacing = 4;
/* selectable */
select = &style->selectable;
nk_zero_struct(*select);
select->normal = nk_style_item_color(table[NK_COLOR_SELECT]);
select->hover = nk_style_item_color(table[NK_COLOR_SELECT]);
select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]);
select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
select->text_normal = table[NK_COLOR_TEXT];
select->text_hover = table[NK_COLOR_TEXT];
select->text_pressed = table[NK_COLOR_TEXT];
select->text_normal_active = table[NK_COLOR_TEXT];
select->text_hover_active = table[NK_COLOR_TEXT];
select->text_pressed_active = table[NK_COLOR_TEXT];
select->padding = nk_vec2(2.0f,2.0f);
select->touch_padding = nk_vec2(0,0);
select->userdata = nk_handle_ptr(0);
select->rounding = 0.0f;
select->draw_begin = 0;
select->draw_end = 0;
/* slider */
slider = &style->slider;
nk_zero_struct(*slider);
slider->normal = nk_style_item_hide();
slider->hover = nk_style_item_hide();
slider->active = nk_style_item_hide();
slider->bar_normal = table[NK_COLOR_SLIDER];
slider->bar_hover = table[NK_COLOR_SLIDER];
slider->bar_active = table[NK_COLOR_SLIDER];
slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR];
slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT;
slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT;
slider->cursor_size = nk_vec2(16,16);
slider->padding = nk_vec2(2,2);
slider->spacing = nk_vec2(2,2);
slider->userdata = nk_handle_ptr(0);
slider->show_buttons = nk_false;
slider->bar_height = 8;
slider->rounding = 0;
slider->draw_begin = 0;
slider->draw_end = 0;
/* slider buttons */
button = &style->slider.inc_button;
button->normal = nk_style_item_color(nk_rgb(40,40,40));
button->hover = nk_style_item_color(nk_rgb(42,42,42));
button->active = nk_style_item_color(nk_rgb(44,44,44));
button->border_color = nk_rgb(65,65,65);
button->text_background = nk_rgb(40,40,40);
button->text_normal = nk_rgb(175,175,175);
button->text_hover = nk_rgb(175,175,175);
button->text_active = nk_rgb(175,175,175);
button->padding = nk_vec2(8.0f,8.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 1.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
style->slider.dec_button = style->slider.inc_button;
/* progressbar */
prog = &style->progress;
nk_zero_struct(*prog);
prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]);
prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]);
prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]);
prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
prog->border_color = nk_rgba(0,0,0,0);
prog->cursor_border_color = nk_rgba(0,0,0,0);
prog->userdata = nk_handle_ptr(0);
prog->padding = nk_vec2(4,4);
prog->rounding = 0;
prog->border = 0;
prog->cursor_rounding = 0;
prog->cursor_border = 0;
prog->draw_begin = 0;
prog->draw_end = 0;
/* scrollbars */
scroll = &style->scrollh;
nk_zero_struct(*scroll);
scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);
scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);
scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);
scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID;
scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID;
scroll->userdata = nk_handle_ptr(0);
scroll->border_color = table[NK_COLOR_SCROLLBAR];
scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];
scroll->padding = nk_vec2(0,0);
scroll->show_buttons = nk_false;
scroll->border = 0;
scroll->rounding = 0;
scroll->border_cursor = 0;
scroll->rounding_cursor = 0;
scroll->draw_begin = 0;
scroll->draw_end = 0;
style->scrollv = style->scrollh;
/* scrollbars buttons */
button = &style->scrollh.inc_button;
button->normal = nk_style_item_color(nk_rgb(40,40,40));
button->hover = nk_style_item_color(nk_rgb(42,42,42));
button->active = nk_style_item_color(nk_rgb(44,44,44));
button->border_color = nk_rgb(65,65,65);
button->text_background = nk_rgb(40,40,40);
button->text_normal = nk_rgb(175,175,175);
button->text_hover = nk_rgb(175,175,175);
button->text_active = nk_rgb(175,175,175);
button->padding = nk_vec2(4.0f,4.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 1.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
style->scrollh.dec_button = style->scrollh.inc_button;
style->scrollv.inc_button = style->scrollh.inc_button;
style->scrollv.dec_button = style->scrollh.inc_button;
/* edit */
edit = &style->edit;
nk_zero_struct(*edit);
edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]);
edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]);
edit->active = nk_style_item_color(table[NK_COLOR_EDIT]);
edit->cursor_normal = table[NK_COLOR_TEXT];
edit->cursor_hover = table[NK_COLOR_TEXT];
edit->cursor_text_normal= table[NK_COLOR_EDIT];
edit->cursor_text_hover = table[NK_COLOR_EDIT];
edit->border_color = table[NK_COLOR_BORDER];
edit->text_normal = table[NK_COLOR_TEXT];
edit->text_hover = table[NK_COLOR_TEXT];
edit->text_active = table[NK_COLOR_TEXT];
edit->selected_normal = table[NK_COLOR_TEXT];
edit->selected_hover = table[NK_COLOR_TEXT];
edit->selected_text_normal = table[NK_COLOR_EDIT];
edit->selected_text_hover = table[NK_COLOR_EDIT];
edit->scrollbar_size = nk_vec2(10,10);
edit->scrollbar = style->scrollv;
edit->padding = nk_vec2(4,4);
edit->row_padding = 2;
edit->cursor_size = 4;
edit->border = 1;
edit->rounding = 0;
/* property */
property = &style->property;
nk_zero_struct(*property);
property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
property->border_color = table[NK_COLOR_BORDER];
property->label_normal = table[NK_COLOR_TEXT];
property->label_hover = table[NK_COLOR_TEXT];
property->label_active = table[NK_COLOR_TEXT];
property->sym_left = NK_SYMBOL_TRIANGLE_LEFT;
property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT;
property->userdata = nk_handle_ptr(0);
property->padding = nk_vec2(4,4);
property->border = 1;
property->rounding = 10;
property->draw_begin = 0;
property->draw_end = 0;
/* property buttons */
button = &style->property.dec_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_PROPERTY];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(0.0f,0.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
style->property.inc_button = style->property.dec_button;
/* property edit */
edit = &style->property.edit;
nk_zero_struct(*edit);
edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
edit->border_color = nk_rgba(0,0,0,0);
edit->cursor_normal = table[NK_COLOR_TEXT];
edit->cursor_hover = table[NK_COLOR_TEXT];
edit->cursor_text_normal= table[NK_COLOR_EDIT];
edit->cursor_text_hover = table[NK_COLOR_EDIT];
edit->text_normal = table[NK_COLOR_TEXT];
edit->text_hover = table[NK_COLOR_TEXT];
edit->text_active = table[NK_COLOR_TEXT];
edit->selected_normal = table[NK_COLOR_TEXT];
edit->selected_hover = table[NK_COLOR_TEXT];
edit->selected_text_normal = table[NK_COLOR_EDIT];
edit->selected_text_hover = table[NK_COLOR_EDIT];
edit->padding = nk_vec2(0,0);
edit->cursor_size = 8;
edit->border = 0;
edit->rounding = 0;
/* chart */
chart = &style->chart;
nk_zero_struct(*chart);
chart->background = nk_style_item_color(table[NK_COLOR_CHART]);
chart->border_color = table[NK_COLOR_BORDER];
chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];
chart->color = table[NK_COLOR_CHART_COLOR];
chart->padding = nk_vec2(4,4);
chart->border = 0;
chart->rounding = 0;
/* combo */
combo = &style->combo;
combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
combo->active = nk_style_item_color(table[NK_COLOR_COMBO]);
combo->border_color = table[NK_COLOR_BORDER];
combo->label_normal = table[NK_COLOR_TEXT];
combo->label_hover = table[NK_COLOR_TEXT];
combo->label_active = table[NK_COLOR_TEXT];
combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN;
combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN;
combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN;
combo->content_padding = nk_vec2(4,4);
combo->button_padding = nk_vec2(0,4);
combo->spacing = nk_vec2(4,0);
combo->border = 1;
combo->rounding = 0;
/* combo button */
button = &style->combo.button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
button->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
button->active = nk_style_item_color(table[NK_COLOR_COMBO]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_COMBO];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* tab */
tab = &style->tab;
tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
tab->border_color = table[NK_COLOR_BORDER];
tab->text = table[NK_COLOR_TEXT];
tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT;
tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN;
tab->padding = nk_vec2(4,4);
tab->spacing = nk_vec2(4,4);
tab->indent = 10.0f;
tab->border = 1;
tab->rounding = 0;
/* tab button */
button = &style->tab.tab_minimize_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_TAB_HEADER];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
style->tab.tab_maximize_button =*button;
/* node button */
button = &style->tab.node_minimize_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_TAB_HEADER];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(2.0f,2.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
style->tab.node_maximize_button =*button;
/* window header */
win = &style->window;
win->header.align = NK_HEADER_RIGHT;
win->header.close_symbol = NK_SYMBOL_X;
win->header.minimize_symbol = NK_SYMBOL_MINUS;
win->header.maximize_symbol = NK_SYMBOL_PLUS;
win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);
win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);
win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);
win->header.label_normal = table[NK_COLOR_TEXT];
win->header.label_hover = table[NK_COLOR_TEXT];
win->header.label_active = table[NK_COLOR_TEXT];
win->header.label_padding = nk_vec2(4,4);
win->header.padding = nk_vec2(4,4);
win->header.spacing = nk_vec2(0,0);
/* window header close button */
button = &style->window.header.close_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_HEADER];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(0.0f,0.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* window header minimize button */
button = &style->window.header.minimize_button;
nk_zero_struct(*button);
button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
button->border_color = nk_rgba(0,0,0,0);
button->text_background = table[NK_COLOR_HEADER];
button->text_normal = table[NK_COLOR_TEXT];
button->text_hover = table[NK_COLOR_TEXT];
button->text_active = table[NK_COLOR_TEXT];
button->padding = nk_vec2(0.0f,0.0f);
button->touch_padding = nk_vec2(0.0f,0.0f);
button->userdata = nk_handle_ptr(0);
button->text_alignment = NK_TEXT_CENTERED;
button->border = 0.0f;
button->rounding = 0.0f;
button->draw_begin = 0;
button->draw_end = 0;
/* window */
win->background = table[NK_COLOR_WINDOW];
win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);
win->border_color = table[NK_COLOR_BORDER];
win->popup_border_color = table[NK_COLOR_BORDER];
win->combo_border_color = table[NK_COLOR_BORDER];
win->contextual_border_color = table[NK_COLOR_BORDER];
win->menu_border_color = table[NK_COLOR_BORDER];
win->group_border_color = table[NK_COLOR_BORDER];
win->tooltip_border_color = table[NK_COLOR_BORDER];
win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);
win->rounding = 0.0f;
win->spacing = nk_vec2(4,4);
win->scrollbar_size = nk_vec2(10,10);
win->min_size = nk_vec2(64,64);
win->combo_border = 1.0f;
win->contextual_border = 1.0f;
win->menu_border = 1.0f;
win->group_border = 1.0f;
win->tooltip_border = 1.0f;
win->popup_border = 1.0f;
win->border = 2.0f;
win->min_row_height_padding = 8;
win->padding = nk_vec2(4,4);
win->group_padding = nk_vec2(4,4);
win->popup_padding = nk_vec2(4,4);
win->combo_padding = nk_vec2(4,4);
win->contextual_padding = nk_vec2(4,4);
win->menu_padding = nk_vec2(4,4);
win->tooltip_padding = nk_vec2(4,4);
}
NK_API void
nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)
{
struct nk_style *style;
NK_ASSERT(ctx);
if (!ctx) return;
style = &ctx->style;
style->font = font;
ctx->stacks.fonts.head = 0;
if (ctx->current)
nk_layout_reset_min_row_height(ctx);
}
NK_API int
nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font)
{
struct nk_config_stack_user_font *font_stack;
struct nk_config_stack_user_font_element *element;
NK_ASSERT(ctx);
if (!ctx) return 0;
font_stack = &ctx->stacks.fonts;
NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));
if (font_stack->head >= (int)NK_LEN(font_stack->elements))
return 0;
element = &font_stack->elements[font_stack->head++];
element->address = &ctx->style.font;
element->old_value = ctx->style.font;
ctx->style.font = font;
return 1;
}
NK_API int
nk_style_pop_font(struct nk_context *ctx)
{
struct nk_config_stack_user_font *font_stack;
struct nk_config_stack_user_font_element *element;
NK_ASSERT(ctx);
if (!ctx) return 0;
font_stack = &ctx->stacks.fonts;
NK_ASSERT(font_stack->head > 0);
if (font_stack->head < 1)
return 0;
element = &font_stack->elements[--font_stack->head];
*element->address = element->old_value;
return 1;
}
#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \
nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\
{\
struct nk_config_stack_##type * type_stack;\
struct nk_config_stack_##type##_element *element;\
NK_ASSERT(ctx);\
if (!ctx) return 0;\
type_stack = &ctx->stacks.stack;\
NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\
if (type_stack->head >= (int)NK_LEN(type_stack->elements))\
return 0;\
element = &type_stack->elements[type_stack->head++];\
element->address = address;\
element->old_value = *address;\
*address = value;\
return 1;\
}
#define NK_STYLE_POP_IMPLEMENATION(type, stack) \
nk_style_pop_##type(struct nk_context *ctx)\
{\
struct nk_config_stack_##type *type_stack;\
struct nk_config_stack_##type##_element *element;\
NK_ASSERT(ctx);\
if (!ctx) return 0;\
type_stack = &ctx->stacks.stack;\
NK_ASSERT(type_stack->head > 0);\
if (type_stack->head < 1)\
return 0;\
element = &type_stack->elements[--type_stack->head];\
*element->address = element->old_value;\
return 1;\
}
NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)
NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)
NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)
NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)
NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)
NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items)
NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats)
NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors)
NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags)
NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors)
NK_API int
nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)
{
struct nk_style *style;
NK_ASSERT(ctx);
if (!ctx) return 0;
style = &ctx->style;
if (style->cursors[c]) {
style->cursor_active = style->cursors[c];
return 1;
}
return 0;
}
NK_API void
nk_style_show_cursor(struct nk_context *ctx)
{
ctx->style.cursor_visible = nk_true;
}
NK_API void
nk_style_hide_cursor(struct nk_context *ctx)
{
ctx->style.cursor_visible = nk_false;
}
NK_API void
nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,
const struct nk_cursor *c)
{
struct nk_style *style;
NK_ASSERT(ctx);
if (!ctx) return;
style = &ctx->style;
style->cursors[cursor] = c;
}
NK_API void
nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors)
{
int i = 0;
struct nk_style *style;
NK_ASSERT(ctx);
if (!ctx) return;
style = &ctx->style;
for (i = 0; i < NK_CURSOR_COUNT; ++i)
style->cursors[i] = &cursors[i];
style->cursor_visible = nk_true;
}

90
src/nuklear_table.c Normal file
View File

@ -0,0 +1,90 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TABLE
*
* ===============================================================*/
NK_LIB struct nk_table*
nk_create_table(struct nk_context *ctx)
{
struct nk_page_element *elem;
elem = nk_create_page_element(ctx);
if (!elem) return 0;
nk_zero_struct(*elem);
return &elem->data.tbl;
}
NK_LIB void
nk_free_table(struct nk_context *ctx, struct nk_table *tbl)
{
union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);
struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
nk_free_page_element(ctx, pe);
}
NK_LIB void
nk_push_table(struct nk_window *win, struct nk_table *tbl)
{
if (!win->tables) {
win->tables = tbl;
tbl->next = 0;
tbl->prev = 0;
tbl->size = 0;
win->table_count = 1;
return;
}
win->tables->prev = tbl;
tbl->next = win->tables;
tbl->prev = 0;
tbl->size = 0;
win->tables = tbl;
win->table_count++;
}
NK_LIB void
nk_remove_table(struct nk_window *win, struct nk_table *tbl)
{
if (win->tables == tbl)
win->tables = tbl->next;
if (tbl->next)
tbl->next->prev = tbl->prev;
if (tbl->prev)
tbl->prev->next = tbl->next;
tbl->next = 0;
tbl->prev = 0;
}
NK_LIB nk_uint*
nk_add_value(struct nk_context *ctx, struct nk_window *win,
nk_hash name, nk_uint value)
{
NK_ASSERT(ctx);
NK_ASSERT(win);
if (!win || !ctx) return 0;
if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) {
struct nk_table *tbl = nk_create_table(ctx);
NK_ASSERT(tbl);
if (!tbl) return 0;
nk_push_table(win, tbl);
}
win->tables->seq = win->seq;
win->tables->keys[win->tables->size] = name;
win->tables->values[win->tables->size] = value;
return &win->tables->values[win->tables->size++];
}
NK_LIB nk_uint*
nk_find_value(struct nk_window *win, nk_hash name)
{
struct nk_table *iter = win->tables;
while (iter) {
unsigned int i = 0;
unsigned int size = iter->size;
for (i = 0; i < size; ++i) {
if (iter->keys[i] == name) {
iter->seq = win->seq;
return &iter->values[i];
}
} size = NK_VALUE_PAGE_CAPACITY;
iter = iter->next;
}
return 0;
}

267
src/nuklear_text.c Normal file
View File

@ -0,0 +1,267 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TEXT
*
* ===============================================================*/
NK_LIB void
nk_widget_text(struct nk_command_buffer *o, struct nk_rect b,
const char *string, int len, const struct nk_text *t,
nk_flags a, const struct nk_user_font *f)
{
struct nk_rect label;
float text_width;
NK_ASSERT(o);
NK_ASSERT(t);
if (!o || !t) return;
b.h = NK_MAX(b.h, 2 * t->padding.y);
label.x = 0; label.w = 0;
label.y = b.y + t->padding.y;
label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);
text_width = f->width(f->userdata, f->height, (const char*)string, len);
text_width += (2.0f * t->padding.x);
/* align in x-axis */
if (a & NK_TEXT_ALIGN_LEFT) {
label.x = b.x + t->padding.x;
label.w = NK_MAX(0, b.w - 2 * t->padding.x);
} else if (a & NK_TEXT_ALIGN_CENTERED) {
label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);
label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);
label.x = NK_MAX(b.x + t->padding.x, label.x);
label.w = NK_MIN(b.x + b.w, label.x + label.w);
if (label.w >= label.x) label.w -= label.x;
} else if (a & NK_TEXT_ALIGN_RIGHT) {
label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));
label.w = (float)text_width + 2 * t->padding.x;
} else return;
/* align in y-axis */
if (a & NK_TEXT_ALIGN_MIDDLE) {
label.y = b.y + b.h/2.0f - (float)f->height/2.0f;
label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));
} else if (a & NK_TEXT_ALIGN_BOTTOM) {
label.y = b.y + b.h - f->height;
label.h = f->height;
}
nk_draw_text(o, label, (const char*)string,
len, f, t->background, t->text);
}
NK_LIB void
nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,
const char *string, int len, const struct nk_text *t,
const struct nk_user_font *f)
{
float width;
int glyphs = 0;
int fitting = 0;
int done = 0;
struct nk_rect line;
struct nk_text text;
NK_INTERN nk_rune seperator[] = {' '};
NK_ASSERT(o);
NK_ASSERT(t);
if (!o || !t) return;
text.padding = nk_vec2(0,0);
text.background = t->background;
text.text = t->text;
b.w = NK_MAX(b.w, 2 * t->padding.x);
b.h = NK_MAX(b.h, 2 * t->padding.y);
b.h = b.h - 2 * t->padding.y;
line.x = b.x + t->padding.x;
line.y = b.y + t->padding.y;
line.w = b.w - 2 * t->padding.x;
line.h = 2 * t->padding.y + f->height;
fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
while (done < len) {
if (!fitting || line.y + line.h >= (b.y + b.h)) break;
nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);
done += fitting;
line.y += f->height + 2 * t->padding.y;
fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
}
}
NK_API void
nk_text_colored(struct nk_context *ctx, const char *str, int len,
nk_flags alignment, struct nk_color color)
{
struct nk_window *win;
const struct nk_style *style;
struct nk_vec2 item_padding;
struct nk_rect bounds;
struct nk_text text;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return;
win = ctx->current;
style = &ctx->style;
nk_panel_alloc_space(&bounds, ctx);
item_padding = style->text.padding;
text.padding.x = item_padding.x;
text.padding.y = item_padding.y;
text.background = style->window.background;
text.text = color;
nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);
}
NK_API void
nk_text_wrap_colored(struct nk_context *ctx, const char *str,
int len, struct nk_color color)
{
struct nk_window *win;
const struct nk_style *style;
struct nk_vec2 item_padding;
struct nk_rect bounds;
struct nk_text text;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout) return;
win = ctx->current;
style = &ctx->style;
nk_panel_alloc_space(&bounds, ctx);
item_padding = style->text.padding;
text.padding.x = item_padding.x;
text.padding.y = item_padding.y;
text.background = style->window.background;
text.text = color;
nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);
}
#ifdef NK_INCLUDE_STANDARD_VARARGS
NK_API void
nk_labelf_colored(struct nk_context *ctx, nk_flags flags,
struct nk_color color, const char *fmt, ...)
{
char buf[256];
va_list args;
va_start(args, fmt);
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_colored(ctx, buf, flags, color);
va_end(args);
}
NK_API void
nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,
const char *fmt, ...)
{
char buf[256];
va_list args;
va_start(args, fmt);
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_colored_wrap(ctx, buf, color);
va_end(args);
}
NK_API void
nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)
{
char buf[256];
va_list args;
va_start(args, fmt);
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label(ctx, buf, flags);
va_end(args);
}
NK_API void
nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)
{
char buf[256];
va_list args;
va_start(args, fmt);
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_wrap(ctx, buf);
va_end(args);
}
NK_API void
nk_value_bool(struct nk_context *ctx, const char *prefix, int value)
{
nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));
}
NK_API void
nk_value_int(struct nk_context *ctx, const char *prefix, int value)
{
nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);
}
NK_API void
nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)
{
nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);
}
NK_API void
nk_value_float(struct nk_context *ctx, const char *prefix, float value)
{
double double_value = (double)value;
nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value);
}
NK_API void
nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)
{
nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);
}
NK_API void
nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)
{
double c[4]; nk_color_dv(c, color);
nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)",
p, c[0], c[1], c[2], c[3]);
}
NK_API void
nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)
{
char hex[16];
nk_color_hex_rgba(hex, color);
nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex);
}
#endif
NK_API void
nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)
{
NK_ASSERT(ctx);
if (!ctx) return;
nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);
}
NK_API void
nk_text_wrap(struct nk_context *ctx, const char *str, int len)
{
NK_ASSERT(ctx);
if (!ctx) return;
nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);
}
NK_API void
nk_label(struct nk_context *ctx, const char *str, nk_flags alignment)
{
nk_text(ctx, str, nk_strlen(str), alignment);
}
NK_API void
nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,
struct nk_color color)
{
nk_text_colored(ctx, str, nk_strlen(str), align, color);
}
NK_API void
nk_label_wrap(struct nk_context *ctx, const char *str)
{
nk_text_wrap(ctx, str, nk_strlen(str));
}
NK_API void
nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)
{
nk_text_wrap_colored(ctx, str, nk_strlen(str), color);
}

1029
src/nuklear_text_editor.c Normal file

File diff suppressed because it is too large Load Diff

320
src/nuklear_toggle.c Normal file
View File

@ -0,0 +1,320 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TOGGLE
*
* ===============================================================*/
NK_LIB int
nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
nk_flags *state, int active)
{
nk_widget_state_reset(state);
if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {
*state = NK_WIDGET_STATE_ACTIVE;
active = !active;
}
if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))
*state |= NK_WIDGET_STATE_ENTERED;
else if (nk_input_is_mouse_prev_hovering_rect(in, select))
*state |= NK_WIDGET_STATE_LEFT;
return active;
}
NK_LIB void
nk_draw_checkbox(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_toggle *style, int active,
const struct nk_rect *label, const struct nk_rect *selector,
const struct nk_rect *cursors, const char *string, int len,
const struct nk_user_font *font)
{
const struct nk_style_item *background;
const struct nk_style_item *cursor;
struct nk_text text;
/* select correct colors/images */
if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
cursor = &style->cursor_hover;
text.text = style->text_hover;
} else if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->hover;
cursor = &style->cursor_hover;
text.text = style->text_active;
} else {
background = &style->normal;
cursor = &style->cursor_normal;
text.text = style->text_normal;
}
/* draw background and cursor */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_fill_rect(out, *selector, 0, style->border_color);
nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color);
} else nk_draw_image(out, *selector, &background->data.image, nk_white);
if (active) {
if (cursor->type == NK_STYLE_ITEM_IMAGE)
nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
else nk_fill_rect(out, *cursors, 0, cursor->data.color);
}
text.padding.x = 0;
text.padding.y = 0;
text.background = style->text_background;
nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
}
NK_LIB void
nk_draw_option(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_toggle *style, int active,
const struct nk_rect *label, const struct nk_rect *selector,
const struct nk_rect *cursors, const char *string, int len,
const struct nk_user_font *font)
{
const struct nk_style_item *background;
const struct nk_style_item *cursor;
struct nk_text text;
/* select correct colors/images */
if (state & NK_WIDGET_STATE_HOVER) {
background = &style->hover;
cursor = &style->cursor_hover;
text.text = style->text_hover;
} else if (state & NK_WIDGET_STATE_ACTIVED) {
background = &style->hover;
cursor = &style->cursor_hover;
text.text = style->text_active;
} else {
background = &style->normal;
cursor = &style->cursor_normal;
text.text = style->text_normal;
}
/* draw background and cursor */
if (background->type == NK_STYLE_ITEM_COLOR) {
nk_fill_circle(out, *selector, style->border_color);
nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color);
} else nk_draw_image(out, *selector, &background->data.image, nk_white);
if (active) {
if (cursor->type == NK_STYLE_ITEM_IMAGE)
nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
else nk_fill_circle(out, *cursors, cursor->data.color);
}
text.padding.x = 0;
text.padding.y = 0;
text.background = style->text_background;
nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
}
NK_LIB int
nk_do_toggle(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect r,
int *active, const char *str, int len, enum nk_toggle_type type,
const struct nk_style_toggle *style, const struct nk_input *in,
const struct nk_user_font *font)
{
int was_active;
struct nk_rect bounds;
struct nk_rect select;
struct nk_rect cursor;
struct nk_rect label;
NK_ASSERT(style);
NK_ASSERT(out);
NK_ASSERT(font);
if (!out || !style || !font || !active)
return 0;
r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);
r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);
/* add additional touch padding for touch screen devices */
bounds.x = r.x - style->touch_padding.x;
bounds.y = r.y - style->touch_padding.y;
bounds.w = r.w + 2 * style->touch_padding.x;
bounds.h = r.h + 2 * style->touch_padding.y;
/* calculate the selector space */
select.w = font->height;
select.h = select.w;
select.y = r.y + r.h/2.0f - select.h/2.0f;
select.x = r.x;
/* calculate the bounds of the cursor inside the selector */
cursor.x = select.x + style->padding.x + style->border;
cursor.y = select.y + style->padding.y + style->border;
cursor.w = select.w - (2 * style->padding.x + 2 * style->border);
cursor.h = select.h - (2 * style->padding.y + 2 * style->border);
/* label behind the selector */
label.x = select.x + select.w + style->spacing;
label.y = select.y;
label.w = NK_MAX(r.x + r.w, label.x) - label.x;
label.h = select.w;
/* update selector */
was_active = *active;
*active = nk_toggle_behavior(in, bounds, state, *active);
/* draw selector */
if (style->draw_begin)
style->draw_begin(out, style->userdata);
if (type == NK_TOGGLE_CHECK) {
nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font);
} else {
nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font);
}
if (style->draw_end)
style->draw_end(out, style->userdata);
return (was_active != *active);
}
/*----------------------------------------------------------------
*
* CHECKBOX
*
* --------------------------------------------------------------*/
NK_API int
nk_check_text(struct nk_context *ctx, const char *text, int len, int active)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return active;
win = ctx->current;
style = &ctx->style;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return active;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font);
return active;
}
NK_API unsigned int
nk_check_flags_text(struct nk_context *ctx, const char *text, int len,
unsigned int flags, unsigned int value)
{
int old_active;
NK_ASSERT(ctx);
NK_ASSERT(text);
if (!ctx || !text) return flags;
old_active = (int)((flags & value) & value);
if (nk_check_text(ctx, text, len, old_active))
flags |= value;
else flags &= ~value;
return flags;
}
NK_API int
nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active)
{
int old_val;
NK_ASSERT(ctx);
NK_ASSERT(text);
NK_ASSERT(active);
if (!ctx || !text || !active) return 0;
old_val = *active;
*active = nk_check_text(ctx, text, len, *active);
return old_val != *active;
}
NK_API int
nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
unsigned int *flags, unsigned int value)
{
int active;
NK_ASSERT(ctx);
NK_ASSERT(text);
NK_ASSERT(flags);
if (!ctx || !text || !flags) return 0;
active = (int)((*flags & value) & value);
if (nk_checkbox_text(ctx, text, len, &active)) {
if (active) *flags |= value;
else *flags &= ~value;
return 1;
}
return 0;
}
NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active)
{
return nk_check_text(ctx, label, nk_strlen(label), active);
}
NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,
unsigned int flags, unsigned int value)
{
return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);
}
NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active)
{
return nk_checkbox_text(ctx, label, nk_strlen(label), active);
}
NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label,
unsigned int *flags, unsigned int value)
{
return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);
}
/*----------------------------------------------------------------
*
* OPTION
*
* --------------------------------------------------------------*/
NK_API int
nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
const struct nk_style *style;
struct nk_rect bounds;
enum nk_widget_layout_states state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return is_active;
win = ctx->current;
style = &ctx->style;
layout = win->layout;
state = nk_widget(&bounds, ctx);
if (!state) return (int)state;
in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
text, len, NK_TOGGLE_OPTION, &style->option, in, style->font);
return is_active;
}
NK_API int
nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active)
{
int old_value;
NK_ASSERT(ctx);
NK_ASSERT(text);
NK_ASSERT(active);
if (!ctx || !text || !active) return 0;
old_value = *active;
*active = nk_option_text(ctx, text, len, old_value);
return old_value != *active;
}
NK_API int
nk_option_label(struct nk_context *ctx, const char *label, int active)
{
return nk_option_text(ctx, label, nk_strlen(label), active);
}
NK_API int
nk_radio_label(struct nk_context *ctx, const char *label, int *active)
{
return nk_radio_text(ctx, label, nk_strlen(label), active);
}

106
src/nuklear_tooltip.c Normal file
View File

@ -0,0 +1,106 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TOOLTIP
*
* ===============================================================*/
NK_API int
nk_tooltip_begin(struct nk_context *ctx, float width)
{
int x,y,w,h;
struct nk_window *win;
const struct nk_input *in;
struct nk_rect bounds;
int ret;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
/* make sure that no nonblocking popup is currently active */
win = ctx->current;
in = &ctx->input;
if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK))
return 0;
w = nk_iceilf(width);
h = nk_iceilf(nk_null_rect.h);
x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x;
y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y;
bounds.x = (float)x;
bounds.y = (float)y;
bounds.w = (float)w;
bounds.h = (float)h;
ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,
"__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);
if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
win->popup.type = NK_PANEL_TOOLTIP;
ctx->current->layout->type = NK_PANEL_TOOLTIP;
return ret;
}
NK_API void
nk_tooltip_end(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return;
ctx->current->seq--;
nk_popup_close(ctx);
nk_popup_end(ctx);
}
NK_API void
nk_tooltip(struct nk_context *ctx, const char *text)
{
const struct nk_style *style;
struct nk_vec2 padding;
int text_len;
float text_width;
float text_height;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
NK_ASSERT(text);
if (!ctx || !ctx->current || !ctx->current->layout || !text)
return;
/* fetch configuration data */
style = &ctx->style;
padding = style->window.padding;
/* calculate size of the text and tooltip */
text_len = nk_strlen(text);
text_width = style->font->width(style->font->userdata,
style->font->height, text, text_len);
text_width += (4 * padding.x);
text_height = (style->font->height + 2 * padding.y);
/* execute tooltip and fill with text */
if (nk_tooltip_begin(ctx, (float)text_width)) {
nk_layout_row_dynamic(ctx, (float)text_height, 1);
nk_text(ctx, text, text_len, NK_TEXT_LEFT);
nk_tooltip_end(ctx);
}
}
#ifdef NK_INCLUDE_STANDARD_VARARGS
NK_API void
nk_tooltipf(struct nk_context *ctx, const char *fmt, ...)
{
char buf[256];
va_list args;
va_start(args, fmt);
nk_strfmt(buf, NK_LEN(buf), fmt, args);
va_end(args);
nk_tooltip(ctx, buf);
}
#endif

189
src/nuklear_tree.c Normal file
View File

@ -0,0 +1,189 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TREE
*
* ===============================================================*/
NK_INTERN int
nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image *img, const char *title, enum nk_collapse_states *state)
{
struct nk_window *win;
struct nk_panel *layout;
const struct nk_style *style;
struct nk_command_buffer *out;
const struct nk_input *in;
const struct nk_style_button *button;
enum nk_symbol_type symbol;
float row_height;
struct nk_vec2 item_spacing;
struct nk_rect header = {0,0,0,0};
struct nk_rect sym = {0,0,0,0};
struct nk_text text;
nk_flags ws = 0;
enum nk_widget_layout_states widget_state;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;
/* cache some data */
win = ctx->current;
layout = win->layout;
out = &win->buffer;
style = &ctx->style;
item_spacing = style->window.spacing;
/* calculate header bounds and draw background */
row_height = style->font->height + 2 * style->tab.padding.y;
nk_layout_set_min_row_height(ctx, row_height);
nk_layout_row_dynamic(ctx, row_height, 1);
nk_layout_reset_min_row_height(ctx);
widget_state = nk_widget(&header, ctx);
if (type == NK_TREE_TAB) {
const struct nk_style_item *background = &style->tab.background;
if (background->type == NK_STYLE_ITEM_IMAGE) {
nk_draw_image(out, header, &background->data.image, nk_white);
text.background = nk_rgba(0,0,0,0);
} else {
text.background = background->data.color;
nk_fill_rect(out, header, 0, style->tab.border_color);
nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
style->tab.rounding, background->data.color);
}
} else text.background = style->window.background;
/* update node state */
in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))
*state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;
/* select correct button style */
if (*state == NK_MAXIMIZED) {
symbol = style->tab.sym_maximize;
if (type == NK_TREE_TAB)
button = &style->tab.tab_maximize_button;
else button = &style->tab.node_maximize_button;
} else {
symbol = style->tab.sym_minimize;
if (type == NK_TREE_TAB)
button = &style->tab.tab_minimize_button;
else button = &style->tab.node_minimize_button;
}
{/* draw triangle button */
sym.w = sym.h = style->font->height;
sym.y = header.y + style->tab.padding.y;
sym.x = header.x + style->tab.padding.x;
nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,
button, 0, style->font);
if (img) {
/* draw optional image icon */
sym.x = sym.x + sym.w + 4 * item_spacing.x;
nk_draw_image(&win->buffer, sym, img, nk_white);
sym.w = style->font->height + style->tab.spacing.x;}
}
{/* draw label */
struct nk_rect label;
header.w = NK_MAX(header.w, sym.w + item_spacing.x);
label.x = sym.x + sym.w + item_spacing.x;
label.y = sym.y;
label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);
label.h = style->font->height;
text.text = style->tab.text;
text.padding = nk_vec2(0,0);
nk_widget_text(out, label, title, nk_strlen(title), &text,
NK_TEXT_LEFT, style->font);}
/* increase x-axis cursor widget position pointer */
if (*state == NK_MAXIMIZED) {
layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
layout->bounds.w -= (style->tab.indent + style->window.padding.x);
layout->row.tree_depth++;
return nk_true;
} else return nk_false;
}
NK_INTERN int
nk_tree_base(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
const char *hash, int len, int line)
{
struct nk_window *win = ctx->current;
int title_len = 0;
nk_hash tree_hash = 0;
nk_uint *state = 0;
/* retrieve tree state from internal widget state tables */
if (!hash) {
title_len = (int)nk_strlen(title);
tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
} else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
state = nk_find_value(win, tree_hash);
if (!state) {
state = nk_add_value(ctx, win, tree_hash, 0);
*state = initial_state;
}
return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);
}
NK_API int
nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,
const char *title, enum nk_collapse_states *state)
{
return nk_tree_state_base(ctx, type, 0, title, state);
}
NK_API int
nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image img, const char *title, enum nk_collapse_states *state)
{
return nk_tree_state_base(ctx, type, &img, title, state);
}
NK_API void
nk_tree_state_pop(struct nk_context *ctx)
{
struct nk_window *win = 0;
struct nk_panel *layout = 0;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
win = ctx->current;
layout = win->layout;
layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x;
layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;
NK_ASSERT(layout->row.tree_depth);
layout->row.tree_depth--;
}
NK_API int
nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
const char *title, enum nk_collapse_states initial_state,
const char *hash, int len, int line)
{
return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);
}
NK_API int
nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image img, const char *title, enum nk_collapse_states initial_state,
const char *hash, int len,int seed)
{
return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);
}
NK_API void
nk_tree_pop(struct nk_context *ctx)
{
nk_tree_state_pop(ctx);
}

144
src/nuklear_utf8.c Normal file
View File

@ -0,0 +1,144 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* UTF-8
*
* ===============================================================*/
NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};
NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
NK_INTERN int
nk_utf_validate(nk_rune *u, int i)
{
NK_ASSERT(u);
if (!u) return 0;
if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||
NK_BETWEEN(*u, 0xD800, 0xDFFF))
*u = NK_UTF_INVALID;
for (i = 1; *u > nk_utfmax[i]; ++i);
return i;
}
NK_INTERN nk_rune
nk_utf_decode_byte(char c, int *i)
{
NK_ASSERT(i);
if (!i) return 0;
for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {
if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])
return (nk_byte)(c & ~nk_utfmask[*i]);
}
return 0;
}
NK_API int
nk_utf_decode(const char *c, nk_rune *u, int clen)
{
int i, j, len, type=0;
nk_rune udecoded;
NK_ASSERT(c);
NK_ASSERT(u);
if (!c || !u) return 0;
if (!clen) return 0;
*u = NK_UTF_INVALID;
udecoded = nk_utf_decode_byte(c[0], &len);
if (!NK_BETWEEN(len, 1, NK_UTF_SIZE))
return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);
if (type != 0)
return j;
}
if (j < len)
return 0;
*u = udecoded;
nk_utf_validate(u, len);
return len;
}
NK_INTERN char
nk_utf_encode_byte(nk_rune u, int i)
{
return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));
}
NK_API int
nk_utf_encode(nk_rune u, char *c, int clen)
{
int len, i;
len = nk_utf_validate(&u, 0);
if (clen < len || !len || len > NK_UTF_SIZE)
return 0;
for (i = len - 1; i != 0; --i) {
c[i] = nk_utf_encode_byte(u, 0);
u >>= 6;
}
c[0] = nk_utf_encode_byte(u, len);
return len;
}
NK_API int
nk_utf_len(const char *str, int len)
{
const char *text;
int glyphs = 0;
int text_len;
int glyph_len;
int src_len = 0;
nk_rune unicode;
NK_ASSERT(str);
if (!str || !len) return 0;
text = str;
text_len = len;
glyph_len = nk_utf_decode(text, &unicode, text_len);
while (glyph_len && src_len < len) {
glyphs++;
src_len = src_len + glyph_len;
glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);
}
return glyphs;
}
NK_API const char*
nk_utf_at(const char *buffer, int length, int index,
nk_rune *unicode, int *len)
{
int i = 0;
int src_len = 0;
int glyph_len = 0;
const char *text;
int text_len;
NK_ASSERT(buffer);
NK_ASSERT(unicode);
NK_ASSERT(len);
if (!buffer || !unicode || !len) return 0;
if (index < 0) {
*unicode = NK_UTF_INVALID;
*len = 0;
return 0;
}
text = buffer;
text_len = length;
glyph_len = nk_utf_decode(text, unicode, text_len);
while (glyph_len) {
if (i == index) {
*len = glyph_len;
break;
}
i++;
src_len = src_len + glyph_len;
glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
}
if (i != index) return 0;
return buffer + src_len;
}

1113
src/nuklear_util.c Normal file

File diff suppressed because it is too large Load Diff

1328
src/nuklear_vertex.c Normal file

File diff suppressed because it is too large Load Diff

246
src/nuklear_widget.c Normal file
View File

@ -0,0 +1,246 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* WIDGET
*
* ===============================================================*/
NK_API struct nk_rect
nk_widget_bounds(struct nk_context *ctx)
{
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return nk_rect(0,0,0,0);
nk_layout_peek(&bounds, ctx);
return bounds;
}
NK_API struct nk_vec2
nk_widget_position(struct nk_context *ctx)
{
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return nk_vec2(0,0);
nk_layout_peek(&bounds, ctx);
return nk_vec2(bounds.x, bounds.y);
}
NK_API struct nk_vec2
nk_widget_size(struct nk_context *ctx)
{
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return nk_vec2(0,0);
nk_layout_peek(&bounds, ctx);
return nk_vec2(bounds.w, bounds.h);
}
NK_API float
nk_widget_width(struct nk_context *ctx)
{
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return 0;
nk_layout_peek(&bounds, ctx);
return bounds.w;
}
NK_API float
nk_widget_height(struct nk_context *ctx)
{
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return 0;
nk_layout_peek(&bounds, ctx);
return bounds.h;
}
NK_API int
nk_widget_is_hovered(struct nk_context *ctx)
{
struct nk_rect c, v;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current || ctx->active != ctx->current)
return 0;
c = ctx->current->layout->clip;
c.x = (float)((int)c.x);
c.y = (float)((int)c.y);
c.w = (float)((int)c.w);
c.h = (float)((int)c.h);
nk_layout_peek(&bounds, ctx);
nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
return 0;
return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
}
NK_API int
nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn)
{
struct nk_rect c, v;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current || ctx->active != ctx->current)
return 0;
c = ctx->current->layout->clip;
c.x = (float)((int)c.x);
c.y = (float)((int)c.y);
c.w = (float)((int)c.w);
c.h = (float)((int)c.h);
nk_layout_peek(&bounds, ctx);
nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
return 0;
return nk_input_mouse_clicked(&ctx->input, btn, bounds);
}
NK_API int
nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down)
{
struct nk_rect c, v;
struct nk_rect bounds;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current || ctx->active != ctx->current)
return 0;
c = ctx->current->layout->clip;
c.x = (float)((int)c.x);
c.y = (float)((int)c.y);
c.w = (float)((int)c.w);
c.h = (float)((int)c.h);
nk_layout_peek(&bounds, ctx);
nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
return 0;
return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);
}
NK_API enum nk_widget_layout_states
nk_widget(struct nk_rect *bounds, const struct nk_context *ctx)
{
struct nk_rect c, v;
struct nk_window *win;
struct nk_panel *layout;
const struct nk_input *in;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return NK_WIDGET_INVALID;
/* allocate space and check if the widget needs to be updated and drawn */
nk_panel_alloc_space(bounds, ctx);
win = ctx->current;
layout = win->layout;
in = &ctx->input;
c = layout->clip;
/* if one of these triggers you forgot to add an `if` condition around either
a window, group, popup, combobox or contextual menu `begin` and `end` block.
Example:
if (nk_begin(...) {...} nk_end(...); or
if (nk_group_begin(...) { nk_group_end(...);} */
NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
/* need to convert to int here to remove floating point errors */
bounds->x = (float)((int)bounds->x);
bounds->y = (float)((int)bounds->y);
bounds->w = (float)((int)bounds->w);
bounds->h = (float)((int)bounds->h);
c.x = (float)((int)c.x);
c.y = (float)((int)c.y);
c.w = (float)((int)c.w);
c.h = (float)((int)c.h);
nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);
if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))
return NK_WIDGET_INVALID;
if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))
return NK_WIDGET_ROM;
return NK_WIDGET_VALID;
}
NK_API enum nk_widget_layout_states
nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx,
struct nk_vec2 item_padding)
{
/* update the bounds to stand without padding */
struct nk_window *win;
struct nk_style *style;
struct nk_panel *layout;
enum nk_widget_layout_states state;
struct nk_vec2 panel_padding;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return NK_WIDGET_INVALID;
win = ctx->current;
style = &ctx->style;
layout = win->layout;
state = nk_widget(bounds, ctx);
panel_padding = nk_panel_get_padding(style, layout->type);
if (layout->row.index == 1) {
bounds->w += panel_padding.x;
bounds->x -= panel_padding.x;
} else bounds->x -= item_padding.x;
if (layout->row.index == layout->row.columns)
bounds->w += panel_padding.x;
else bounds->w += item_padding.x;
return state;
}
NK_API void
nk_spacing(struct nk_context *ctx, int cols)
{
struct nk_window *win;
struct nk_panel *layout;
struct nk_rect none;
int i, index, rows;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return;
/* spacing over row boundaries */
win = ctx->current;
layout = win->layout;
index = (layout->row.index + cols) % layout->row.columns;
rows = (layout->row.index + cols) / layout->row.columns;
if (rows) {
for (i = 0; i < rows; ++i)
nk_panel_alloc_row(ctx, win);
cols = index;
}
/* non table layout need to allocate space */
if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&
layout->row.type != NK_LAYOUT_STATIC_FIXED) {
for (i = 0; i < cols; ++i)
nk_panel_alloc_space(&none, ctx);
} layout->row.index = index;
}

641
src/nuklear_window.c Normal file
View File

@ -0,0 +1,641 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* WINDOW
*
* ===============================================================*/
NK_LIB void*
nk_create_window(struct nk_context *ctx)
{
struct nk_page_element *elem;
elem = nk_create_page_element(ctx);
if (!elem) return 0;
elem->data.win.seq = ctx->seq;
return &elem->data.win;
}
NK_LIB void
nk_free_window(struct nk_context *ctx, struct nk_window *win)
{
/* unlink windows from list */
struct nk_table *it = win->tables;
if (win->popup.win) {
nk_free_window(ctx, win->popup.win);
win->popup.win = 0;
}
win->next = 0;
win->prev = 0;
while (it) {
/*free window state tables */
struct nk_table *n = it->next;
nk_remove_table(win, it);
nk_free_table(ctx, it);
if (it == win->tables)
win->tables = n;
it = n;
}
/* link windows into freelist */
{union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);
struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
nk_free_page_element(ctx, pe);}
}
NK_LIB struct nk_window*
nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name)
{
struct nk_window *iter;
iter = ctx->begin;
while (iter) {
NK_ASSERT(iter != iter->next);
if (iter->name == hash) {
int max_len = nk_strlen(iter->name_string);
if (!nk_stricmpn(iter->name_string, name, max_len))
return iter;
}
iter = iter->next;
}
return 0;
}
NK_LIB void
nk_insert_window(struct nk_context *ctx, struct nk_window *win,
enum nk_window_insert_location loc)
{
const struct nk_window *iter;
NK_ASSERT(ctx);
NK_ASSERT(win);
if (!win || !ctx) return;
iter = ctx->begin;
while (iter) {
NK_ASSERT(iter != iter->next);
NK_ASSERT(iter != win);
if (iter == win) return;
iter = iter->next;
}
if (!ctx->begin) {
win->next = 0;
win->prev = 0;
ctx->begin = win;
ctx->end = win;
ctx->count = 1;
return;
}
if (loc == NK_INSERT_BACK) {
struct nk_window *end;
end = ctx->end;
end->flags |= NK_WINDOW_ROM;
end->next = win;
win->prev = ctx->end;
win->next = 0;
ctx->end = win;
ctx->active = ctx->end;
ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
} else {
/*ctx->end->flags |= NK_WINDOW_ROM;*/
ctx->begin->prev = win;
win->next = ctx->begin;
win->prev = 0;
ctx->begin = win;
ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;
}
ctx->count++;
}
NK_LIB void
nk_remove_window(struct nk_context *ctx, struct nk_window *win)
{
if (win == ctx->begin || win == ctx->end) {
if (win == ctx->begin) {
ctx->begin = win->next;
if (win->next)
win->next->prev = 0;
}
if (win == ctx->end) {
ctx->end = win->prev;
if (win->prev)
win->prev->next = 0;
}
} else {
if (win->next)
win->next->prev = win->prev;
if (win->prev)
win->prev->next = win->next;
}
if (win == ctx->active || !ctx->active) {
ctx->active = ctx->end;
if (ctx->end)
ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
}
win->next = 0;
win->prev = 0;
ctx->count--;
}
NK_API int
nk_begin(struct nk_context *ctx, const char *title,
struct nk_rect bounds, nk_flags flags)
{
return nk_begin_titled(ctx, title, title, bounds, flags);
}
NK_API int
nk_begin_titled(struct nk_context *ctx, const char *name, const char *title,
struct nk_rect bounds, nk_flags flags)
{
struct nk_window *win;
struct nk_style *style;
nk_hash title_hash;
int title_len;
int ret = 0;
NK_ASSERT(ctx);
NK_ASSERT(name);
NK_ASSERT(title);
NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font");
NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call");
if (!ctx || ctx->current || !title || !name)
return 0;
/* find or create window */
style = &ctx->style;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) {
/* create new window */
nk_size name_length = (nk_size)nk_strlen(name);
win = (struct nk_window*)nk_create_window(ctx);
NK_ASSERT(win);
if (!win) return 0;
if (flags & NK_WINDOW_BACKGROUND)
nk_insert_window(ctx, win, NK_INSERT_FRONT);
else nk_insert_window(ctx, win, NK_INSERT_BACK);
nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);
win->flags = flags;
win->bounds = bounds;
win->name = title_hash;
name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);
NK_MEMCPY(win->name_string, name, name_length);
win->name_string[name_length] = 0;
win->popup.win = 0;
if (!ctx->active)
ctx->active = win;
} else {
/* update window */
win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);
win->flags |= flags;
if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))
win->bounds = bounds;
/* If this assert triggers you either:
*
* I.) Have more than one window with the same name or
* II.) You forgot to actually draw the window.
* More specific you did not call `nk_clear` (nk_clear will be
* automatically called for you if you are using one of the
* provided demo backends). */
NK_ASSERT(win->seq != ctx->seq);
win->seq = ctx->seq;
if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) {
ctx->active = win;
ctx->end = win;
}
}
if (win->flags & NK_WINDOW_HIDDEN) {
ctx->current = win;
win->layout = 0;
return 0;
} else nk_start(ctx, win);
/* window overlapping */
if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))
{
int inpanel, ishovered;
struct nk_window *iter = win;
float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +
(2.0f * style->window.header.label_padding.y);
struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?
win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);
/* activate window if hovered and no other window is overlapping this window */
inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);
inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;
ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);
if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {
iter = win->next;
while (iter) {
struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
(!(iter->flags & NK_WINDOW_HIDDEN)))
break;
if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
iter->popup.win->bounds.x, iter->popup.win->bounds.y,
iter->popup.win->bounds.w, iter->popup.win->bounds.h))
break;
iter = iter->next;
}
}
/* activate window if clicked */
if (iter && inpanel && (win != ctx->end)) {
iter = win->next;
while (iter) {
/* try to find a panel with higher priority in the same position */
struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,
iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
!(iter->flags & NK_WINDOW_HIDDEN))
break;
if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
iter->popup.win->bounds.x, iter->popup.win->bounds.y,
iter->popup.win->bounds.w, iter->popup.win->bounds.h))
break;
iter = iter->next;
}
}
if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) {
win->flags |= (nk_flags)NK_WINDOW_ROM;
iter->flags &= ~(nk_flags)NK_WINDOW_ROM;
ctx->active = iter;
if (!(iter->flags & NK_WINDOW_BACKGROUND)) {
/* current window is active in that position so transfer to top
* at the highest priority in stack */
nk_remove_window(ctx, iter);
nk_insert_window(ctx, iter, NK_INSERT_BACK);
}
} else {
if (!iter && ctx->end != win) {
if (!(win->flags & NK_WINDOW_BACKGROUND)) {
/* current window is active in that position so transfer to top
* at the highest priority in stack */
nk_remove_window(ctx, win);
nk_insert_window(ctx, win, NK_INSERT_BACK);
}
win->flags &= ~(nk_flags)NK_WINDOW_ROM;
ctx->active = win;
}
if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))
win->flags |= NK_WINDOW_ROM;
}
}
win->layout = (struct nk_panel*)nk_create_panel(ctx);
ctx->current = win;
ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);
win->layout->offset_x = &win->scrollbar.x;
win->layout->offset_y = &win->scrollbar.y;
return ret;
}
NK_API void
nk_end(struct nk_context *ctx)
{
struct nk_panel *layout;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`");
if (!ctx || !ctx->current)
return;
layout = ctx->current->layout;
if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {
ctx->current = 0;
return;
}
nk_panel_end(ctx);
nk_free_panel(ctx, ctx->current->layout);
ctx->current = 0;
}
NK_API struct nk_rect
nk_window_get_bounds(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
return ctx->current->bounds;
}
NK_API struct nk_vec2
nk_window_get_position(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return nk_vec2(0,0);
return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);
}
NK_API struct nk_vec2
nk_window_get_size(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return nk_vec2(0,0);
return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);
}
NK_API float
nk_window_get_width(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return 0;
return ctx->current->bounds.w;
}
NK_API float
nk_window_get_height(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return 0;
return ctx->current->bounds.h;
}
NK_API struct nk_rect
nk_window_get_content_region(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
return ctx->current->layout->clip;
}
NK_API struct nk_vec2
nk_window_get_content_region_min(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current) return nk_vec2(0,0);
return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);
}
NK_API struct nk_vec2
nk_window_get_content_region_max(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current) return nk_vec2(0,0);
return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,
ctx->current->layout->clip.y + ctx->current->layout->clip.h);
}
NK_API struct nk_vec2
nk_window_get_content_region_size(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current) return nk_vec2(0,0);
return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);
}
NK_API struct nk_command_buffer*
nk_window_get_canvas(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current) return 0;
return &ctx->current->buffer;
}
NK_API struct nk_panel*
nk_window_get_panel(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return 0;
return ctx->current->layout;
}
NK_API int
nk_window_has_focus(const struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current) return 0;
return ctx->current == ctx->active;
}
NK_API int
nk_window_is_hovered(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current) return 0;
if(ctx->current->flags & NK_WINDOW_HIDDEN)
return 0;
return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds);
}
NK_API int
nk_window_is_any_hovered(struct nk_context *ctx)
{
struct nk_window *iter;
NK_ASSERT(ctx);
if (!ctx) return 0;
iter = ctx->begin;
while (iter) {
/* check if window is being hovered */
if(!(iter->flags & NK_WINDOW_HIDDEN)) {
/* check if window popup is being hovered */
if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))
return 1;
if (iter->flags & NK_WINDOW_MINIMIZED) {
struct nk_rect header = iter->bounds;
header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;
if (nk_input_is_mouse_hovering_rect(&ctx->input, header))
return 1;
} else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {
return 1;
}
}
iter = iter->next;
}
return 0;
}
NK_API int
nk_item_is_any_active(struct nk_context *ctx)
{
int any_hovered = nk_window_is_any_hovered(ctx);
int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
return any_hovered || any_active;
}
NK_API int
nk_window_is_collapsed(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return 0;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return 0;
return win->flags & NK_WINDOW_MINIMIZED;
}
NK_API int
nk_window_is_closed(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return 1;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return 1;
return (win->flags & NK_WINDOW_CLOSED);
}
NK_API int
nk_window_is_hidden(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return 1;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return 1;
return (win->flags & NK_WINDOW_HIDDEN);
}
NK_API int
nk_window_is_active(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return 0;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return 0;
return win == ctx->active;
}
NK_API struct nk_window*
nk_window_find(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
return nk_find_window(ctx, title_hash, name);
}
NK_API void
nk_window_close(struct nk_context *ctx, const char *name)
{
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
win = nk_window_find(ctx, name);
if (!win) return;
NK_ASSERT(ctx->current != win && "You cannot close a currently active window");
if (ctx->current == win) return;
win->flags |= NK_WINDOW_HIDDEN;
win->flags |= NK_WINDOW_CLOSED;
}
NK_API void
nk_window_set_bounds(struct nk_context *ctx,
const char *name, struct nk_rect bounds)
{
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
win = nk_window_find(ctx, name);
if (!win) return;
NK_ASSERT(ctx->current != win && "You cannot update a currently in procecss window");
win->bounds = bounds;
}
NK_API void
nk_window_set_position(struct nk_context *ctx,
const char *name, struct nk_vec2 pos)
{
struct nk_window *win = nk_window_find(ctx, name);
if (!win) return;
win->bounds.x = pos.x;
win->bounds.y = pos.y;
}
NK_API void
nk_window_set_size(struct nk_context *ctx,
const char *name, struct nk_vec2 size)
{
struct nk_window *win = nk_window_find(ctx, name);
if (!win) return;
win->bounds.w = size.x;
win->bounds.h = size.y;
}
NK_API void
nk_window_collapse(struct nk_context *ctx, const char *name,
enum nk_collapse_states c)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return;
if (c == NK_MINIMIZED)
win->flags |= NK_WINDOW_MINIMIZED;
else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;
}
NK_API void
nk_window_collapse_if(struct nk_context *ctx, const char *name,
enum nk_collapse_states c, int cond)
{
NK_ASSERT(ctx);
if (!ctx || !cond) return;
nk_window_collapse(ctx, name, c);
}
NK_API void
nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (!win) return;
if (s == NK_HIDDEN) {
win->flags |= NK_WINDOW_HIDDEN;
} else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;
}
NK_API void
nk_window_show_if(struct nk_context *ctx, const char *name,
enum nk_show_states s, int cond)
{
NK_ASSERT(ctx);
if (!ctx || !cond) return;
nk_window_show(ctx, name, s);
}
NK_API void
nk_window_set_focus(struct nk_context *ctx, const char *name)
{
int title_len;
nk_hash title_hash;
struct nk_window *win;
NK_ASSERT(ctx);
if (!ctx) return;
title_len = (int)nk_strlen(name);
title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, title_hash, name);
if (win && ctx->end != win) {
nk_remove_window(ctx, win);
nk_insert_window(ctx, win, NK_INSERT_BACK);
}
ctx->active = win;
}

3
src/paq.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
python build.py --macro NK --intro HEADER --pub nuklear.h --priv nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c,nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS