diff --git a/.gitignore b/.gitignore index 8b09aff..3e055ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,32 @@ -# Object files -*.o -*.ko -*.obj -*.elf - -# Libraries -*.lib -*.a - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# KDevelop -*.kdev4* - -# Build -bin/ -build/ +# Object files +*.o +*.ko +*.obj +*.elf + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# KDevelop +*.kdev4* + +# Build +bin/ +build/ +Debug/ +Release/ diff --git a/Android.mk b/Android.mk index edb1187..476b598 100755 --- a/Android.mk +++ b/Android.mk @@ -1,21 +1,21 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -SDL_PATH := ../SDL -SDL_TTF_PATH := ../SDL_ttf - -LOCAL_MODULE := KiWi_static -LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include $(LOCAL_PATH)/$(SDL_TTF_PATH) - -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src - -LOCAL_SRC_FILES := \ - $(subst $(LOCAL_PATH)/,, \ - $(wildcard $(LOCAL_PATH)/src/*.c)) - -LOCAL_MODULE_FILENAME := libKiWi - -LOCAL_STATIC_LIBRARIES := SDL2_static SDL2_ttf_static - -include $(BUILD_STATIC_LIBRARY) +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +SDL_PATH := ../SDL +SDL_TTF_PATH := ../SDL_ttf + +LOCAL_MODULE := KiWi_static +LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include $(LOCAL_PATH)/$(SDL_TTF_PATH) + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src + +LOCAL_SRC_FILES := \ + $(subst $(LOCAL_PATH)/,, \ + $(wildcard $(LOCAL_PATH)/src/*.c)) + +LOCAL_MODULE_FILENAME := libKiWi + +LOCAL_STATIC_LIBRARIES := SDL2_static SDL2_ttf_static + +include $(BUILD_STATIC_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index 684914b..7953a2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,64 +1,64 @@ -project(KiWi) -cmake_minimum_required(VERSION 2.8) - -# Point to our own cmake modules -list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake-modules) - -# Define this as top-level -set(KIWI_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/src) - -# Add global definitions -add_definitions("-Wno-unused-functions -Wall") - -# Add Debug definitions -set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") - -option(DEBUG_GEOMETRY_CHANGE "Print a lot of messages when calculating composed geometries" OFF) -if (DEBUG_GEOMETRY_CHANGE) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG_GEOMETRY_CHANGE") -endif() - -option(DEBUG_PRINT_GEOMETRY_RECTANGLE "Display composed geometry rectangles of widgets" OFF) -if (DEBUG_PRINT_GEOMETRY_RECTANGLE) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG_PRINT_GEOMETRY_RECTANGLE") -endif() - -if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fvisibility=hidden -std=c89 -pedantic-errors") -endif(CMAKE_COMPILER_IS_GNUCC) - -# Add subdirectories -add_subdirectory(src) -add_subdirectory(examples) - -# Install KiWiConfig stuff -set(INCLUDE_INSTALL_DIR include/KiWi) -set(LIB_INSTALL_DIR lib) -export(PACKAGE KiWi) -if (UNIX) - set(CMAKECONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") -elseif(WIN32) - set(CMAKECONFIG_INSTALL_DIR "cmake" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") -elseif(APPLE) - set(CMAKECONFIG_INSTALL_DIR "cmake" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") -endif() - -include(CMakePackageConfigHelpers) -configure_package_config_file(KiWiConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/tmpkiwiconfig - INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} - PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) -write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/KiWiConfigVersion.cmake - VERSION 0.0.1 - COMPATIBILITY SameMajorVersion) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/KiWiConfigVersion.cmake - DESTINATION ${CMAKECONFIG_INSTALL_DIR}) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/tmpkiwiconfig - RENAME KiWiConfig.cmake - DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) - -# install KiWiTargets.cmake -install(EXPORT KiWiTargets DESTINATION ${CMAKECONFIG_INSTALL_DIR}) +project(KiWi) +cmake_minimum_required(VERSION 2.8) + +# Point to our own cmake modules +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake-modules) + +# Define this as top-level +set(KIWI_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/src) + +# Add global definitions +add_definitions("-Wno-unused-functions -Wall") + +# Add Debug definitions +set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") + +option(DEBUG_GEOMETRY_CHANGE "Print a lot of messages when calculating composed geometries" OFF) +if (DEBUG_GEOMETRY_CHANGE) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG_GEOMETRY_CHANGE") +endif() + +option(DEBUG_PRINT_GEOMETRY_RECTANGLE "Display composed geometry rectangles of widgets" OFF) +if (DEBUG_PRINT_GEOMETRY_RECTANGLE) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG_PRINT_GEOMETRY_RECTANGLE") +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fvisibility=hidden -std=c89 -pedantic-errors") +endif(CMAKE_COMPILER_IS_GNUCC) + +# Add subdirectories +add_subdirectory(src) +add_subdirectory(examples) + +# Install KiWiConfig stuff +set(INCLUDE_INSTALL_DIR include/KiWi) +set(LIB_INSTALL_DIR lib) +export(PACKAGE KiWi) +if (UNIX) + set(CMAKECONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") +elseif(WIN32) + set(CMAKECONFIG_INSTALL_DIR "cmake" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") +elseif(APPLE) + set(CMAKECONFIG_INSTALL_DIR "cmake" CACHE STRING "Where ${PROJECT_NAME}-config.cmake and companions will be installed") +endif() + +include(CMakePackageConfigHelpers) +configure_package_config_file(KiWiConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/tmpkiwiconfig + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/KiWiConfigVersion.cmake + VERSION 0.0.1 + COMPATIBILITY SameMajorVersion) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/KiWiConfigVersion.cmake + DESTINATION ${CMAKECONFIG_INSTALL_DIR}) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/tmpkiwiconfig + RENAME KiWiConfig.cmake + DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) + +# install KiWiTargets.cmake +install(EXPORT KiWiTargets DESTINATION ${CMAKECONFIG_INSTALL_DIR}) diff --git a/KiWi.vcxproj b/KiWi.vcxproj new file mode 100644 index 0000000..6fecb65 --- /dev/null +++ b/KiWi.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {32485B92-3CFD-4645-A5AA-E21A2479B9E4} + Win32Proj + KiWi + + + + StaticLibrary + true + v110 + Unicode + + + StaticLibrary + false + v110 + true + Unicode + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)\SDL\include;$(SolutionDir)\SDL_image;$(SolutionDir)\SDL_ttf; + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/KiWiConfig.cmake.in b/KiWiConfig.cmake.in index 19ea2c5..cae4ffd 100644 --- a/KiWiConfig.cmake.in +++ b/KiWiConfig.cmake.in @@ -1,16 +1,16 @@ -set(KiWi_VERSION "@KIWI_VERSION@") -set(KIWI_VERSION "@KIWI_VERSION@") - -@PACKAGE_INIT@ - -set_and_check(KIWI_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") -set_and_check(KIWI_LIBRARY_DIR "@PACKAGE_LIB_INSTALL_DIR@") - -if (NOT TARGET KiWi) - include(${CMAKE_CURRENT_LIST_DIR}/KiWiTargets.cmake) -endif() - -set(KIWI_LIBRARY KiWi) -set(KiWi_LIBRARY ${KIWI_LIBRARY}) -set(KiWi_LIBRARY_DIR ${KIWI_LIBRARY_DIR}) -set(KiWi_INCLUDE_DIR ${KIWI_INCLUDE_DIR}) +set(KiWi_VERSION "@KIWI_VERSION@") +set(KIWI_VERSION "@KIWI_VERSION@") + +@PACKAGE_INIT@ + +set_and_check(KIWI_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(KIWI_LIBRARY_DIR "@PACKAGE_LIB_INSTALL_DIR@") + +if (NOT TARGET KiWi) + include(${CMAKE_CURRENT_LIST_DIR}/KiWiTargets.cmake) +endif() + +set(KIWI_LIBRARY KiWi) +set(KiWi_LIBRARY ${KIWI_LIBRARY}) +set(KiWi_LIBRARY_DIR ${KIWI_LIBRARY_DIR}) +set(KiWi_INCLUDE_DIR ${KIWI_INCLUDE_DIR}) diff --git a/LICENSE b/LICENSE index c044183..78b5bd6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -Copyright (c) 2014, Leonardo Guilherme de Freitas -All rights reserved. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. +Copyright (c) 2014, Leonardo Guilherme de Freitas +All rights reserved. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/README.md b/README.md index 9a15f2c..6850282 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,100 @@ -KiWi - The Killer Widgets library -================================= - -*Killer Widgets* (KiWi) is a widget-based GUI library for game developers to use in their 2D games. Its widgets are constructed by using a tileset, allowing you to easly customize the looks of your GUI by simply changing its tiles (even in runtime, yay!). - -It supports custom (and composed) widgets so that you can implement that beautiful ring chart showing how much network traffic your MMORPG is using, allowing you to impress your boss. - -KiWi is built around SDL2 and designed to accompany it (means that if you want to use KiWi, you'll have to use SDL. But hey, SDL is awesome already, no big deal, right? :) - -Right now KiWi is under (heavy) development and any help (code patches, money, chat, hug, etc) is hugely appreciated. - -Here are some screenshots, though (click on them to see code): - -[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/playground/playground-screenshot.png "Playground screenshot")](https://github.com/leonardo2d/KiWi/blob/master/examples/playground/playground.c) -[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/frame-family/frame-family-screenshot.png "A Family of Frames")](https://github.com/leonardo2d/KiWi/blob/master/examples/frame-family/frame-family.c) - -[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/editbox/editbox-screenshot.png "Two Editboxes and a button")](https://github.com/leonardo2d/KiWi/blob/master/examples/editbox/editbox.c) -[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/styleswitcher/styleswitcher-screenshot.gif "Two Editboxes and a button")](https://github.com/leonardo2d/KiWi/blob/master/examples/styleswitcher/styleswitcher.c) - -[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/scrollbox/scrollbox-screenshot.gif "A scrollbox full of dragable buttons")](https://github.com/leonardo2d/KiWi/blob/master/examples/scrollbox/scrollbox.c) - -Check the [roadmap]! - -## Build and test KiWi: - -If you're feeling mighty and want to try KiWi right now, these are (roughly) the steps to do it: - -1. Have a compiler environment ready (GCC, LLVM, MSVC, MinGW, etc); -2. Have [SDL2], [SDL2_ttf] and [SDL2_image] available and properly detectable by your compiler; -3. Have [CMake](http://cmake.org) installed; -4. Download this repository; -5. Create a `build` folder inside it; -6. Run `cmake` (or `cmake-gui`), set the binary dir to the newly created build folder and the source dir to the repository folder; -7. Build it! - -You can test the examples inside the `build/examples/` folder. - -## Basic usage - -Here is a very basic code that draws a label on screen (taken from the -[playground] example): - -```cpp -#include "SDL.h" -#include "SDL_ttf.h" -#include "SDL_image.h" -#include "KW_gui.h" - -int main(int argc, char ** argv) { - /* init SDL and SDL_ttf */ - SDL_Renderer * renderer; - SDL_Window * window; - SDL_Surface * set; - KW_GUI * gui; - TTF_Font * font; - KW_Widget * frame; - SDL_Rect geometry; - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); - - TTF_Init(); - - /* load tileset surface */ - - set = IMG_Load("tileset.png"); - - /* load font */ - font = TTF_OpenFont("Fontin-Regular.ttf", 12); - - /* init KiWi */ - gui = KW_Init(renderer, set); - KW_SetFont(gui, font); - - /* create a frame and a label on top of it. */ - geometry.x = geometry.y = 0; geometry.w = 320; geometry.h = 240; - frame = KW_CreateFrame(gui, NULL, &geometry); - KW_CreateLabel(gui, frame, "Label", &geometry); - - while (!SDL_QuitRequested()) { - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_Delay(1); - SDL_RenderPresent(renderer); - } - KW_Quit(gui); - SDL_FreeSurface(set); - - return 0; -} -``` - -Better documentation is yet to come, but every public method is well documented. - -[playground]:https://github.com/leonardo2d/KiWi/blob/master/examples/playground/playground.c -[KW_CreateWidget]: https://github.com/leonardo2d/KiWi/blob/master/src/KW_widget.h#L106 -[SDL2]: http://libsdl.org -[SDL2_ttf]: https://www.libsdl.org/projects/SDL_ttf/ -[SDL2_image]: https://www.libsdl.org/projects/SDL_image/ -[roadmap]: https://github.com/leonardo2d/KiWi/blob/master/ROADMAP.md +KiWi - The Killer Widgets library +================================= + +*Killer Widgets* (KiWi) is a widget-based GUI library for game developers to use in their 2D games. Its widgets are constructed by using a tileset, allowing you to easly customize the looks of your GUI by simply changing its tiles (even in runtime, yay!). + +It supports custom (and composed) widgets so that you can implement that beautiful ring chart showing how much network traffic your MMORPG is using, allowing you to impress your boss. + +KiWi is built around SDL2 and designed to accompany it (means that if you want to use KiWi, you'll have to use SDL. But hey, SDL is awesome already, no big deal, right? :) + +Right now KiWi is under (heavy) development and any help (code patches, money, chat, hug, etc) is hugely appreciated. + +Here are some screenshots, though (click on them to see code): + +[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/playground/playground-screenshot.png "Playground screenshot")](https://github.com/leonardo2d/KiWi/blob/master/examples/playground/playground.c) +[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/frame-family/frame-family-screenshot.png "A Family of Frames")](https://github.com/leonardo2d/KiWi/blob/master/examples/frame-family/frame-family.c) + +[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/editbox/editbox-screenshot.png "Two Editboxes and a button")](https://github.com/leonardo2d/KiWi/blob/master/examples/editbox/editbox.c) +[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/styleswitcher/styleswitcher-screenshot.gif "Two Editboxes and a button")](https://github.com/leonardo2d/KiWi/blob/master/examples/styleswitcher/styleswitcher.c) + +[![alt text](https://raw.githubusercontent.com/leonardo2d/KiWi/master/examples/scrollbox/scrollbox-screenshot.gif "A scrollbox full of dragable buttons")](https://github.com/leonardo2d/KiWi/blob/master/examples/scrollbox/scrollbox.c) + +Check the [roadmap]! + +## Build and test KiWi: + +If you're feeling mighty and want to try KiWi right now, these are (roughly) the steps to do it: + +1. Have a compiler environment ready (GCC, LLVM, MSVC, MinGW, etc); +2. Have [SDL2], [SDL2_ttf] and [SDL2_image] available and properly detectable by your compiler; +3. Have [CMake](http://cmake.org) installed; +4. Download this repository; +5. Create a `build` folder inside it; +6. Run `cmake` (or `cmake-gui`), set the binary dir to the newly created build folder and the source dir to the repository folder; +7. Build it! + +You can test the examples inside the `build/examples/` folder. + +## Basic usage + +Here is a very basic code that draws a label on screen (taken from the +[playground] example): + +```cpp +#include "SDL.h" +#include "SDL_ttf.h" +#include "SDL_image.h" +#include "KW_gui.h" + +int main(int argc, char ** argv) { + /* init SDL and SDL_ttf */ + SDL_Renderer * renderer; + SDL_Window * window; + SDL_Surface * set; + KW_GUI * gui; + TTF_Font * font; + KW_Widget * frame; + SDL_Rect geometry; + SDL_Init(SDL_INIT_EVERYTHING); + SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); + + TTF_Init(); + + /* load tileset surface */ + + set = IMG_Load("tileset.png"); + + /* load font */ + font = TTF_OpenFont("Fontin-Regular.ttf", 12); + + /* init KiWi */ + gui = KW_Init(renderer, set); + KW_SetFont(gui, font); + + /* create a frame and a label on top of it. */ + geometry.x = geometry.y = 0; geometry.w = 320; geometry.h = 240; + frame = KW_CreateFrame(gui, NULL, &geometry); + KW_CreateLabel(gui, frame, "Label", &geometry); + + while (!SDL_QuitRequested()) { + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_Delay(1); + SDL_RenderPresent(renderer); + } + KW_Quit(gui); + SDL_FreeSurface(set); + + return 0; +} +``` + +Better documentation is yet to come, but every public method is well documented. + +[playground]:https://github.com/leonardo2d/KiWi/blob/master/examples/playground/playground.c +[KW_CreateWidget]: https://github.com/leonardo2d/KiWi/blob/master/src/KW_widget.h#L106 +[SDL2]: http://libsdl.org +[SDL2_ttf]: https://www.libsdl.org/projects/SDL_ttf/ +[SDL2_image]: https://www.libsdl.org/projects/SDL_image/ +[roadmap]: https://github.com/leonardo2d/KiWi/blob/master/ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md index 539a8f3..f05b669 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,89 +1,89 @@ -# The KiWi Roadmap - -This is a list of planned features for KiWi and their development status. - -Label: **done (bold)**, *in progress (italics)*, to do (no style). - -### Core -- *System/general Events* - - **Mouseover** - - **Focus Gain/Lose** - - **Text editing** - - **Press/release** - - **Drag (Start/Move/Stop)** -- *Widget events* - - **Geometry changed** - - Parent changed - - **Children added** -- *Tile renderer* - - **Fill an area with a tile** - - **Render a frame based on a set of tiles** - - *Stretch tiles instead of multiple tile rendering if user decides so* -- *Text renderer* - - **Render UTF-8 text** - - Render UTF-8 wrapped text - - -### Widgets -- *Frames* - - **Daw a frame with a set of tiles** - - Support for labeled frames (?) -- *Labels* - - **Vertical alignment** - - **Horizontal alignment** - - **Support for icons in labels** - - Label changed event - - Multi-line (wrapped) labels -- *Buttons* - - **Handle mouse events** - - Handle touch events properly - - ButtonPressed (according to core press event) and ButtonReleased (if core release or core focus lose while pressed?) -- *Editboxes* - - **States for mouse over and clicked (active)** - - Support for text replacing (insert key), replacing the cursor. - - Text changed event - - **Proper support for UTF-8** - - *Support for TEXTEDITING events (i.e, Android swype, IME, etc)* - - Multi-line editboxes. -- Progress bars - - Frame progress bar with filled/non-filled bg - - Percent changed events. -- Sliders -- Tables - - Check if really needed. -- Tabs/tabbed views - - KW_AddTabPage() API (decide the API) - - Events for tab page changed, etc. - - Decide on which tiles are needed. -- Checkboxes - - Checked changed events - - Tile for not checked, hover, checked, hover-checked, clicked, clicked-checked. - - Display labels for each item -- Radio group and buttons - - CurrentSelected changed events for the group - - Checked changed events for the items - - Tile for not checked, hover, checked, hover-checked, clicked, clicked-checked. - - Display labels for each item -- *Scrollboxes* - - **Clip children widgets to parent area** (done in the renderer) - - **Clip events for clipped children** - - **Implement the scrollbar** - - **Implement scroll buttons** - - **Have scrollbars change width** - -### Layouts - -- Core - - Decide if they are widgets or separate things - - Make layouts control their widgets geometries - - Pros of being widgets: - - Can have layouts as children widgets of other widgets - - Can have layouts as children of layouts for nestedness greatness - - Cons: - - They aren't really widgets... or are they? -- Form layout - - A two column by N lines grid -- Grid layout - - Can put widgets in any place in the grid -- Horizontal and vertical layouts -- Nested layouts +# The KiWi Roadmap + +This is a list of planned features for KiWi and their development status. + +Label: **done (bold)**, *in progress (italics)*, to do (no style). + +### Core +- *System/general Events* + - **Mouseover** + - **Focus Gain/Lose** + - **Text editing** + - **Press/release** + - **Drag (Start/Move/Stop)** +- *Widget events* + - **Geometry changed** + - Parent changed + - **Children added** +- *Tile renderer* + - **Fill an area with a tile** + - **Render a frame based on a set of tiles** + - *Stretch tiles instead of multiple tile rendering if user decides so* +- *Text renderer* + - **Render UTF-8 text** + - Render UTF-8 wrapped text + + +### Widgets +- *Frames* + - **Daw a frame with a set of tiles** + - Support for labeled frames (?) +- *Labels* + - **Vertical alignment** + - **Horizontal alignment** + - **Support for icons in labels** + - Label changed event + - Multi-line (wrapped) labels +- *Buttons* + - **Handle mouse events** + - Handle touch events properly + - ButtonPressed (according to core press event) and ButtonReleased (if core release or core focus lose while pressed?) +- *Editboxes* + - **States for mouse over and clicked (active)** + - Support for text replacing (insert key), replacing the cursor. + - Text changed event + - **Proper support for UTF-8** + - *Support for TEXTEDITING events (i.e, Android swype, IME, etc)* + - Multi-line editboxes. +- Progress bars + - Frame progress bar with filled/non-filled bg + - Percent changed events. +- Sliders +- Tables + - Check if really needed. +- Tabs/tabbed views + - KW_AddTabPage() API (decide the API) + - Events for tab page changed, etc. + - Decide on which tiles are needed. +- Checkboxes + - Checked changed events + - Tile for not checked, hover, checked, hover-checked, clicked, clicked-checked. + - Display labels for each item +- Radio group and buttons + - CurrentSelected changed events for the group + - Checked changed events for the items + - Tile for not checked, hover, checked, hover-checked, clicked, clicked-checked. + - Display labels for each item +- *Scrollboxes* + - **Clip children widgets to parent area** (done in the renderer) + - **Clip events for clipped children** + - **Implement the scrollbar** + - **Implement scroll buttons** + - **Have scrollbars change width** + +### Layouts + +- Core + - Decide if they are widgets or separate things + - Make layouts control their widgets geometries + - Pros of being widgets: + - Can have layouts as children widgets of other widgets + - Can have layouts as children of layouts for nestedness greatness + - Cons: + - They aren't really widgets... or are they? +- Form layout + - A two column by N lines grid +- Grid layout + - Can put widgets in any place in the grid +- Horizontal and vertical layouts +- Nested layouts diff --git a/cmake-modules/FindSDL2.cmake b/cmake-modules/FindSDL2.cmake index 77e77dd..13ac81d 100644 --- a/cmake-modules/FindSDL2.cmake +++ b/cmake-modules/FindSDL2.cmake @@ -1,179 +1,179 @@ -# Locate SDL2 library -# This module defines -# SDL2_LIBRARY, the name of the library to link against -# SDL2_FOUND, if false, do not try to link to SDL2 -# SDL2_INCLUDE_DIR, where to find SDL.h -# SDL2_LIBRARY_DIR, where to find SDL2.lib -# -# This module responds to the the flag: -# SDL2_BUILDING_LIBRARY -# If this is defined, then no SDL2main will be linked in because -# only applications need main(). -# Otherwise, it is assumed you are building an application and this -# module will attempt to locate and set the the proper link flags -# as part of the returned SDL2_LIBRARY variable. -# -# Don't forget to include SDLmain.h and SDLmain.m your project for the -# OS X framework based version. (Other versions link to -lSDL2main which -# this module will try to find on your behalf.) Also for OS X, this -# module will automatically add the -framework Cocoa on your behalf. -# -# -# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration -# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library -# (SDL2.dll, libsdl2.so, SDL2.framework, etc). -# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. -# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value -# as appropriate. These values are used to generate the final SDL2_LIBRARY -# variable, but when these values are unset, SDL2_LIBRARY does not get created. -# -# -# $SDL2DIR is an environment variable that would -# correspond to the ./configure --prefix=$SDL2DIR -# used in building SDL2. -# l.e.galup 9-20-02 -# -# Modified by Eric Wing. -# Added code to assist with automated building by using environmental variables -# and providing a more controlled/consistent search behavior. -# Added new modifications to recognize OS X frameworks and -# additional Unix paths (FreeBSD, etc). -# Also corrected the header search path to follow "proper" SDL guidelines. -# Added a search for SDL2main which is needed by some platforms. -# Added a search for threads which is needed by some platforms. -# Added needed compile switches for MinGW. -# -# On OSX, this will prefer the Framework version (if found) over others. -# People will have to manually change the cache values of -# SDL2_LIBRARY to override this selection or set the CMake environment -# CMAKE_INCLUDE_PATH to modify the search paths. -# -# Note that the header path has changed from SDL2/SDL.h to just SDL.h -# This needed to change because "proper" SDL convention -# is #include "SDL.h", not . This is done for portability -# reasons because not all systems place things in SDL2/ (see FreeBSD). - -#============================================================================= -# Copyright 2003-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(SDL2_ARCH_64 TRUE) - set(SDL2_PROCESSOR_ARCH "x64") -else() - set(SDL2_ARCH_64 FALSE) - set(SDL2_PROCESSOR_ARCH "x86") -endif(CMAKE_SIZEOF_VOID_P EQUAL 8) - -SET(SDL2_SEARCH_PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ${SDL2_ROOT} -) - -FIND_PATH(SDL2_INCLUDE_DIR SDL.h - HINTS - $ENV{SDL2DIR} - PATH_SUFFIXES include/SDL2 include - PATHS ${SDL2_SEARCH_PATHS} -) - -FIND_LIBRARY(SDL2_LIBRARY_TEMP - NAMES SDL2 - HINTS - $ENV{SDL2DIR} - PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} - PATHS ${SDL2_SEARCH_PATHS} -) - -IF(NOT SDL2_BUILDING_LIBRARY) - IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") - # Non-OS X framework versions expect you to also dynamically link to - # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms - # seem to provide SDL2main for compatibility even though they don't - # necessarily need it. - FIND_LIBRARY(SDL2MAIN_LIBRARY - NAMES SDL2main - HINTS - $ENV{SDL2DIR} - PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} - PATHS ${SDL2_SEARCH_PATHS} - ) - ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") -ENDIF(NOT SDL2_BUILDING_LIBRARY) - -# SDL2 may require threads on your system. -# The Apple build may not need an explicit flag because one of the -# frameworks may already provide it. -# But for non-OSX systems, I will use the CMake Threads package. -IF(NOT APPLE) - FIND_PACKAGE(Threads) -ENDIF(NOT APPLE) - -# MinGW needs an additional library, mwindows -# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows -# (Actually on second look, I think it only needs one of the m* libraries.) -IF(MINGW) - SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") -ENDIF(MINGW) - -IF(SDL2_LIBRARY_TEMP) - SET(SDL2_ORIGINAL_LIBRARY ${SDL2_LIBRARY_TEMP}) - get_filename_component(SDL2_LIBRARY_DIR ${SDL2_ORIGINAL_LIBRARY} PATH) - - # For SDL2main - IF(NOT SDL2_BUILDING_LIBRARY) - IF(SDL2MAIN_LIBRARY) - SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) - ENDIF(SDL2MAIN_LIBRARY) - ENDIF(NOT SDL2_BUILDING_LIBRARY) - - # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. - # CMake doesn't display the -framework Cocoa string in the UI even - # though it actually is there if I modify a pre-used variable. - # I think it has something to do with the CACHE STRING. - # So I use a temporary variable until the end so I can set the - # "real" variable in one-shot. - IF(APPLE) - SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") - ENDIF(APPLE) - - # For threads, as mentioned Apple doesn't need this. - # In fact, there seems to be a problem if I used the Threads package - # and try using this line, so I'm just skipping it entirely for OS X. - IF(NOT APPLE) - SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) - ENDIF(NOT APPLE) - - # For MinGW library - IF(MINGW) - SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) - ENDIF(MINGW) - - # Set the final string here so the GUI reflects the final state. - SET(SDL2_LIBRARY ${SDL2_ORIGINAL_LIBRARY} CACHE STRING "Where the SDL2 Library can be found") - SET(SDL2_LIBRARIES ${SDL2_LIBRARY_TEMP} CACHE STRING "All libraries to link against when using SDL2") - # Set the temp variable to INTERNAL so it is not seen in the CMake GUI - SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") - SET(SDL2_LIBRARY_TEMP "${SDL2_ORIGINAL_LIBRARY}" CACHE INTERNAL "") - SET(SDL2_FOUND "YES") -ENDIF(SDL2_LIBRARY_TEMP) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# SDL2_LIBRARY_DIR, where to find SDL2.lib +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDLmain.h and SDLmain.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(SDL2_ARCH_64 TRUE) + set(SDL2_PROCESSOR_ARCH "x64") +else() + set(SDL2_ARCH_64 FALSE) + set(SDL2_PROCESSOR_ARCH "x86") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + +SET(SDL2_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt + ${SDL2_ROOT} +) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS ${SDL2_SEARCH_PATHS} +) + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} + PATHS ${SDL2_SEARCH_PATHS} +) + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} + PATHS ${SDL2_SEARCH_PATHS} + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +IF(SDL2_LIBRARY_TEMP) + SET(SDL2_ORIGINAL_LIBRARY ${SDL2_LIBRARY_TEMP}) + get_filename_component(SDL2_LIBRARY_DIR ${SDL2_ORIGINAL_LIBRARY} PATH) + + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_ORIGINAL_LIBRARY} CACHE STRING "Where the SDL2 Library can be found") + SET(SDL2_LIBRARIES ${SDL2_LIBRARY_TEMP} CACHE STRING "All libraries to link against when using SDL2") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + SET(SDL2_LIBRARY_TEMP "${SDL2_ORIGINAL_LIBRARY}" CACHE INTERNAL "") + SET(SDL2_FOUND "YES") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/cmake-modules/FindSDL2_image.cmake b/cmake-modules/FindSDL2_image.cmake index 5b1339b..c76aace 100644 --- a/cmake-modules/FindSDL2_image.cmake +++ b/cmake-modules/FindSDL2_image.cmake @@ -1,111 +1,111 @@ -# - Locate SDL_image library -# This module defines: -# SDL2_IMAGE_LIBRARIES, the name of the library to link against -# SDL2_IMAGE_INCLUDE_DIRS, where to find the headers -# SDL2_IMAGE_FOUND, if false, do not try to link against -# SDL2_IMAGE_VERSION_STRING - human-readable string containing the version of SDL_image -# -# For backward compatiblity the following variables are also set: -# SDLIMAGE_LIBRARY (same value as SDL2_IMAGE_LIBRARIES) -# SDLIMAGE_INCLUDE_DIR (same value as SDL2_IMAGE_INCLUDE_DIRS) -# SDLIMAGE_FOUND (same value as SDL2_IMAGE_FOUND) -# -# $SDLDIR is an environment variable that would -# correspond to the ./configure --prefix=$SDLDIR -# used in building SDL. -# -# Created by Eric Wing. This was influenced by the FindSDL.cmake -# module, but with modifications to recognize OS X frameworks and -# additional Unix paths (FreeBSD, etc). - -#============================================================================= -# Copyright 2005-2009 Kitware, Inc. -# Copyright 2012 Benjamin Eikel -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -SET(SDL2_SEARCH_PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ${SDL2_IMAGE_ROOT} - ${SDL2_ROOT} -) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(SDL2_ARCH_64 TRUE) - set(SDL2_PROCESSOR_ARCH "x64") -else() - set(SDL2_ARCH_64 FALSE) - set(SDL2_PROCESSOR_ARCH "x86") -endif(CMAKE_SIZEOF_VOID_P EQUAL 8) - -if(NOT SDL2_IMAGE_INCLUDE_DIR AND SDL2IMAGE_INCLUDE_DIR) - set(SDL2_IMAGE_INCLUDE_DIR ${SDL2IMAGE_INCLUDE_DIR} CACHE PATH "directory cache -entry initialized from old variable name") -endif() -find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h - HINTS - ENV SDL2IMAGEDIR - ENV SDL2DIR - PATH_SUFFIXES include include/SDL2 - PATHS ${SDL2_SEARCH_PATHS} -) - -if(NOT SDL2_IMAGE_LIBRARY AND SDL2IMAGE_LIBRARY) - set(SDL2_IMAGE_LIBRARY ${SDL2IMAGE_LIBRARY} CACHE FILEPATH "file cache entry -initialized from old variable name") -endif() -find_library(SDL2_IMAGE_LIBRARY - NAMES SDL2_image - HINTS - ENV SDL2IMAGEDIR - ENV SDL2DIR - PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} - PATHS ${SDL2_SEARCH_PATHS} -) - -if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}") - set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH}) - unset(SDL2_IMAGE_VERSION_MAJOR_LINE) - unset(SDL2_IMAGE_VERSION_MINOR_LINE) - unset(SDL2_IMAGE_VERSION_PATCH_LINE) - unset(SDL2_IMAGE_VERSION_MAJOR) - unset(SDL2_IMAGE_VERSION_MINOR) - unset(SDL2_IMAGE_VERSION_PATCH) -endif() - -set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY}) -set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image - REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS - VERSION_VAR SDL2_IMAGE_VERSION_STRING) - -# for backward compatiblity -set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES}) -set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS}) -set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND}) - -mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) +# - Locate SDL_image library +# This module defines: +# SDL2_IMAGE_LIBRARIES, the name of the library to link against +# SDL2_IMAGE_INCLUDE_DIRS, where to find the headers +# SDL2_IMAGE_FOUND, if false, do not try to link against +# SDL2_IMAGE_VERSION_STRING - human-readable string containing the version of SDL_image +# +# For backward compatiblity the following variables are also set: +# SDLIMAGE_LIBRARY (same value as SDL2_IMAGE_LIBRARIES) +# SDLIMAGE_INCLUDE_DIR (same value as SDL2_IMAGE_INCLUDE_DIRS) +# SDLIMAGE_FOUND (same value as SDL2_IMAGE_FOUND) +# +# $SDLDIR is an environment variable that would +# correspond to the ./configure --prefix=$SDLDIR +# used in building SDL. +# +# Created by Eric Wing. This was influenced by the FindSDL.cmake +# module, but with modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). + +#============================================================================= +# Copyright 2005-2009 Kitware, Inc. +# Copyright 2012 Benjamin Eikel +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +SET(SDL2_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt + ${SDL2_IMAGE_ROOT} + ${SDL2_ROOT} +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(SDL2_ARCH_64 TRUE) + set(SDL2_PROCESSOR_ARCH "x64") +else() + set(SDL2_ARCH_64 FALSE) + set(SDL2_PROCESSOR_ARCH "x86") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + +if(NOT SDL2_IMAGE_INCLUDE_DIR AND SDL2IMAGE_INCLUDE_DIR) + set(SDL2_IMAGE_INCLUDE_DIR ${SDL2IMAGE_INCLUDE_DIR} CACHE PATH "directory cache +entry initialized from old variable name") +endif() +find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h + HINTS + ENV SDL2IMAGEDIR + ENV SDL2DIR + PATH_SUFFIXES include include/SDL2 + PATHS ${SDL2_SEARCH_PATHS} +) + +if(NOT SDL2_IMAGE_LIBRARY AND SDL2IMAGE_LIBRARY) + set(SDL2_IMAGE_LIBRARY ${SDL2IMAGE_LIBRARY} CACHE FILEPATH "file cache entry +initialized from old variable name") +endif() +find_library(SDL2_IMAGE_LIBRARY + NAMES SDL2_image + HINTS + ENV SDL2IMAGEDIR + ENV SDL2DIR + PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} + PATHS ${SDL2_SEARCH_PATHS} +) + +if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}") + set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH}) + unset(SDL2_IMAGE_VERSION_MAJOR_LINE) + unset(SDL2_IMAGE_VERSION_MINOR_LINE) + unset(SDL2_IMAGE_VERSION_PATCH_LINE) + unset(SDL2_IMAGE_VERSION_MAJOR) + unset(SDL2_IMAGE_VERSION_MINOR) + unset(SDL2_IMAGE_VERSION_PATCH) +endif() + +set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY}) +set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image + REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS + VERSION_VAR SDL2_IMAGE_VERSION_STRING) + +# for backward compatiblity +set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES}) +set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS}) +set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND}) + +mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) diff --git a/cmake-modules/FindSDL2_ttf.cmake b/cmake-modules/FindSDL2_ttf.cmake index 8f27f3b..d9f0f1d 100644 --- a/cmake-modules/FindSDL2_ttf.cmake +++ b/cmake-modules/FindSDL2_ttf.cmake @@ -1,111 +1,111 @@ -# - Locate SDL_ttf library -# This module defines: -# SDL2_TTF_LIBRARIES, the name of the library to link against -# SDL2_TTF_INCLUDE_DIRS, where to find the headers -# SDL2_TTF_FOUND, if false, do not try to link against -# SDL2_TTF_VERSION_STRING - human-readable string containing the version of SDL_ttf -# -# For backward compatiblity the following variables are also set: -# SDLTTF_LIBRARY (same value as SDL2_TTF_LIBRARIES) -# SDLTTF_INCLUDE_DIR (same value as SDL2_TTF_INCLUDE_DIRS) -# SDLTTF_FOUND (same value as SDL2_TTF_FOUND) -# -# $SDLDIR is an environment variable that would -# correspond to the ./configure --prefix=$SDLDIR -# used in building SDL. -# -# Created by Eric Wing. This was influenced by the FindSDL.cmake -# module, but with modifications to recognize OS X frameworks and -# additional Unix paths (FreeBSD, etc). - -#============================================================================= -# Copyright 2005-2009 Kitware, Inc. -# Copyright 2012 Benjamin Eikel -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -SET(SDL2_SEARCH_PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - ${SDL2_TTF_ROOT} - ${SDL2_ROOT} -) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(SDL2_ARCH_64 TRUE) - set(SDL2_PROCESSOR_ARCH "x64") -else() - set(SDL2_ARCH_64 FALSE) - set(SDL2_PROCESSOR_ARCH "x86") -endif(CMAKE_SIZEOF_VOID_P EQUAL 8) - -if(NOT SDL2_TTF_INCLUDE_DIR AND SDL2TTF_INCLUDE_DIR) - set(SDL2_TTF_INCLUDE_DIR ${SDL2TTF_INCLUDE_DIR} CACHE PATH "directory cache -entry initialized from old variable name") -endif() -find_path(SDL2_TTF_INCLUDE_DIR SDL_ttf.h - HINTS - ENV SDL2TTFDIR - ENV SDL2DIR - PATH_SUFFIXES include include/SDL2 include/SDL - PATHS ${SDL2_SEARCH_PATHS} -) - -if(NOT SDL2_TTF_LIBRARY AND SDL2TTF_LIBRARY) - set(SDL2_TTF_LIBRARY ${SDL2TTF_LIBRARY} CACHE FILEPATH "file cache entry -initialized from old variable name") -endif() -find_library(SDL2_TTF_LIBRARY - NAMES SDL2_ttf - HINTS - ENV SDL2TTFDIR - ENV SDL2DIR - PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} - PATHS ${SDL2_SEARCH_PATHS} -) - -if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h") - file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}") - set(SDL2_TTF_VERSION_STRING ${SDL2_TTF_VERSION_MAJOR}.${SDL2_TTF_VERSION_MINOR}.${SDL2_TTF_VERSION_PATCH}) - unset(SDL2_TTF_VERSION_MAJOR_LINE) - unset(SDL2_TTF_VERSION_MINOR_LINE) - unset(SDL2_TTF_VERSION_PATCH_LINE) - unset(SDL2_TTF_VERSION_MAJOR) - unset(SDL2_TTF_VERSION_MINOR) - unset(SDL2_TTF_VERSION_PATCH) -endif() - -set(SDL2_TTF_LIBRARIES ${SDL2_TTF_LIBRARY}) -set(SDL2_TTF_INCLUDE_DIRS ${SDL2_TTF_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_ttf - REQUIRED_VARS SDL2_TTF_LIBRARIES SDL2_TTF_INCLUDE_DIRS - VERSION_VAR SDL2_TTF_VERSION_STRING) - -# for backward compatiblity -set(SDL2TTF_LIBRARY ${SDL2_TTF_LIBRARIES}) -set(SDL2TTF_INCLUDE_DIR ${SDL2_TTF_INCLUDE_DIRS}) -set(SDL2TTF_FOUND ${SDL2_TTF_FOUND}) - -mark_as_advanced(SDL2_TTF_LIBRARY SDL2_TTF_INCLUDE_DIR) +# - Locate SDL_ttf library +# This module defines: +# SDL2_TTF_LIBRARIES, the name of the library to link against +# SDL2_TTF_INCLUDE_DIRS, where to find the headers +# SDL2_TTF_FOUND, if false, do not try to link against +# SDL2_TTF_VERSION_STRING - human-readable string containing the version of SDL_ttf +# +# For backward compatiblity the following variables are also set: +# SDLTTF_LIBRARY (same value as SDL2_TTF_LIBRARIES) +# SDLTTF_INCLUDE_DIR (same value as SDL2_TTF_INCLUDE_DIRS) +# SDLTTF_FOUND (same value as SDL2_TTF_FOUND) +# +# $SDLDIR is an environment variable that would +# correspond to the ./configure --prefix=$SDLDIR +# used in building SDL. +# +# Created by Eric Wing. This was influenced by the FindSDL.cmake +# module, but with modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). + +#============================================================================= +# Copyright 2005-2009 Kitware, Inc. +# Copyright 2012 Benjamin Eikel +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +SET(SDL2_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt + ${SDL2_TTF_ROOT} + ${SDL2_ROOT} +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(SDL2_ARCH_64 TRUE) + set(SDL2_PROCESSOR_ARCH "x64") +else() + set(SDL2_ARCH_64 FALSE) + set(SDL2_PROCESSOR_ARCH "x86") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + +if(NOT SDL2_TTF_INCLUDE_DIR AND SDL2TTF_INCLUDE_DIR) + set(SDL2_TTF_INCLUDE_DIR ${SDL2TTF_INCLUDE_DIR} CACHE PATH "directory cache +entry initialized from old variable name") +endif() +find_path(SDL2_TTF_INCLUDE_DIR SDL_ttf.h + HINTS + ENV SDL2TTFDIR + ENV SDL2DIR + PATH_SUFFIXES include include/SDL2 include/SDL + PATHS ${SDL2_SEARCH_PATHS} +) + +if(NOT SDL2_TTF_LIBRARY AND SDL2TTF_LIBRARY) + set(SDL2_TTF_LIBRARY ${SDL2TTF_LIBRARY} CACHE FILEPATH "file cache entry +initialized from old variable name") +endif() +find_library(SDL2_TTF_LIBRARY + NAMES SDL2_ttf + HINTS + ENV SDL2TTFDIR + ENV SDL2DIR + PATH_SUFFIXES lib64 lib lib/${SDL2_PROCESSOR_ARCH} + PATHS ${SDL2_SEARCH_PATHS} +) + +if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h") + file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}") + set(SDL2_TTF_VERSION_STRING ${SDL2_TTF_VERSION_MAJOR}.${SDL2_TTF_VERSION_MINOR}.${SDL2_TTF_VERSION_PATCH}) + unset(SDL2_TTF_VERSION_MAJOR_LINE) + unset(SDL2_TTF_VERSION_MINOR_LINE) + unset(SDL2_TTF_VERSION_PATCH_LINE) + unset(SDL2_TTF_VERSION_MAJOR) + unset(SDL2_TTF_VERSION_MINOR) + unset(SDL2_TTF_VERSION_PATCH) +endif() + +set(SDL2_TTF_LIBRARIES ${SDL2_TTF_LIBRARY}) +set(SDL2_TTF_INCLUDE_DIRS ${SDL2_TTF_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_ttf + REQUIRED_VARS SDL2_TTF_LIBRARIES SDL2_TTF_INCLUDE_DIRS + VERSION_VAR SDL2_TTF_VERSION_STRING) + +# for backward compatiblity +set(SDL2TTF_LIBRARY ${SDL2_TTF_LIBRARIES}) +set(SDL2TTF_INCLUDE_DIR ${SDL2_TTF_INCLUDE_DIRS}) +set(SDL2TTF_FOUND ${SDL2_TTF_FOUND}) + +mark_as_advanced(SDL2_TTF_LIBRARY SDL2_TTF_INCLUDE_DIR) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 47dd477..083786c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,23 +1,23 @@ -# Find SDL2 -find_package(SDL2 REQUIRED) - -# Include relevat dirs -include_directories(${SDL2_INCLUDE_DIR} ${KIWI_INCLUDE_DIR}) - -# The playground example -add_subdirectory(playground) - -# Frame family example -add_subdirectory(frame-family) - -# Editbox example -add_subdirectory(editbox) - -# Styleswitcher example -#add_subdirectory(styleswitcher) - -# Scroll area example -#add_subdirectory(scrollbox) - -# Drag widget example -#add_subdirectory(drag) +# Find SDL2 +find_package(SDL2 REQUIRED) + +# Include relevat dirs +include_directories(${SDL2_INCLUDE_DIR} ${KIWI_INCLUDE_DIR}) + +# The playground example +add_subdirectory(playground) + +# Frame family example +add_subdirectory(frame-family) + +# Editbox example +add_subdirectory(editbox) + +# Styleswitcher example +add_subdirectory(styleswitcher) + +# Scroll area example +add_subdirectory(scrollbox) + +# Drag widget example +add_subdirectory(drag) diff --git a/examples/drag/CMakeLists.txt b/examples/drag/CMakeLists.txt index e984751..3e7cd83 100644 --- a/examples/drag/CMakeLists.txt +++ b/examples/drag/CMakeLists.txt @@ -1,25 +1,25 @@ -project(drag) -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") -set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") - -foreach(TILESET ${TILESETS}) - add_custom_command(OUTPUT ${TILESET} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} - ) -endforeach(TILESET ${TILESETS}) - -foreach(FONT ${FONTS}) - add_custom_command(OUTPUT ${FONT} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} - ) -endforeach(FONT ${FONTS}) - -add_executable(drag drag.c ${FONTS} ${TILESETS}) -target_link_libraries(drag KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) +project(drag) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") +set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") + +foreach(TILESET ${TILESETS}) + add_custom_command(OUTPUT ${TILESET} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} + ) +endforeach(TILESET ${TILESETS}) + +foreach(FONT ${FONTS}) + add_custom_command(OUTPUT ${FONT} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} + ) +endforeach(FONT ${FONTS}) + +add_executable(drag drag.c ${FONTS} ${TILESETS}) +target_link_libraries(drag KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) diff --git a/examples/drag/drag.c b/examples/drag/drag.c index 945c6f5..447173f 100644 --- a/examples/drag/drag.c +++ b/examples/drag/drag.c @@ -1,89 +1,89 @@ -#include "SDL.h" -#include "KW_gui.h" -#include "KW_button.h" -#include "SDL_image.h" -#include "KW_frame.h" - -int dragmode = 0; - -void DragStart(KW_Widget * widget, int x, int y) { - SDL_Rect g; - KW_GetWidgetAbsoluteGeometry(widget, &g); - if (x > g.x + g.w - 20 && y > g.y + g.h -20) dragmode = 1; - else dragmode = 0; - printf("Drag has started at %dx%d\n", x, y); -} - -void DragStop(KW_Widget * widget, int x, int y) { - printf("Drag has stopped at %dx%d\n", x, y); -} - -void Drag(KW_Widget * widget, int x, int y, int xrel, int yrel) { - SDL_Rect g; - KW_GetWidgetGeometry(widget, &g); - if (dragmode == 1) { - g.w += xrel; - g.h += yrel; - } else { - g.x += xrel; - g.y += yrel; - } - KW_SetWidgetGeometry(widget, &g); -} - - -int main(int argc, char ** argv) { - - /* initialize window and renderer */ - SDL_Window * window; - SDL_Renderer * renderer; - SDL_Surface * set; - KW_GUI * gui; - TTF_Font * font; - SDL_Rect framegeom; - KW_Widget * frame, *a; - int i = 0; - - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(640, 480, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); - TTF_Init(); - - /* load tileset */ - set = IMG_Load("tileset.png"); - - /* initialize gui */ - gui = KW_Init(renderer, set); - font = TTF_OpenFont("Fontin-Regular.ttf", 12); - KW_SetFont(gui, font); - frame = NULL; - framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; - framegeom.x = 50, framegeom.y = 50, framegeom.w = 100, framegeom.h = 100; - frame = KW_CreateFrame(gui, frame, &framegeom); - framegeom.x = 10, framegeom.y = 10, framegeom.w = 160, framegeom.h = 120; - KW_AddWidgetDragHandler(frame, Drag); - for (i = 0; i < 2; i++) { - framegeom.x = framegeom.y = i * 10; - a = KW_CreateButton(gui, frame, "Yay", &framegeom); - KW_AddWidgetDragStartHandler(a, DragStart); - KW_AddWidgetDragStopHandler(a, DragStop); - KW_AddWidgetDragHandler(a, Drag); - } - - while (!SDL_QuitRequested()) { - SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_RenderPresent(renderer); - SDL_Delay(1); - } - - /* free stuff */ - KW_Quit(gui); - TTF_CloseFont(font); - SDL_FreeSurface(set); - TTF_Quit(); - SDL_Quit(); - - return 0; -} +#include "SDL.h" +#include "KW_gui.h" +#include "KW_button.h" +#include "SDL_image.h" +#include "KW_frame.h" + +int dragmode = 0; + +void DragStart(KW_Widget * widget, int x, int y) { + SDL_Rect g; + KW_GetWidgetAbsoluteGeometry(widget, &g); + if (x > g.x + g.w - 20 && y > g.y + g.h -20) dragmode = 1; + else dragmode = 0; + printf("Drag has started at %dx%d\n", x, y); +} + +void DragStop(KW_Widget * widget, int x, int y) { + printf("Drag has stopped at %dx%d\n", x, y); +} + +void Drag(KW_Widget * widget, int x, int y, int xrel, int yrel) { + SDL_Rect g; + KW_GetWidgetGeometry(widget, &g); + if (dragmode == 1) { + g.w += xrel; + g.h += yrel; + } else { + g.x += xrel; + g.y += yrel; + } + KW_SetWidgetGeometry(widget, &g); +} + + +int main(int argc, char ** argv) { + + /* initialize window and renderer */ + SDL_Window * window; + SDL_Renderer * renderer; + SDL_Surface * set; + KW_GUI * gui; + TTF_Font * font; + SDL_Rect framegeom; + KW_Widget * frame, *a; + int i = 0; + + SDL_Init(SDL_INIT_EVERYTHING); + SDL_CreateWindowAndRenderer(640, 480, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); + TTF_Init(); + + /* load tileset */ + set = IMG_Load("tileset.png"); + + /* initialize gui */ + gui = KW_Init(renderer, set); + font = TTF_OpenFont("Fontin-Regular.ttf", 12); + KW_SetFont(gui, font); + frame = NULL; + framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; + framegeom.x = 50, framegeom.y = 50, framegeom.w = 100, framegeom.h = 100; + frame = KW_CreateFrame(gui, frame, &framegeom); + framegeom.x = 10, framegeom.y = 10, framegeom.w = 160, framegeom.h = 120; + KW_AddWidgetDragHandler(frame, Drag); + for (i = 0; i < 2; i++) { + framegeom.x = framegeom.y = i * 10; + a = KW_CreateButton(gui, frame, "Yay", &framegeom); + KW_AddWidgetDragStartHandler(a, DragStart); + KW_AddWidgetDragStopHandler(a, DragStop); + KW_AddWidgetDragHandler(a, Drag); + } + + while (!SDL_QuitRequested()) { + SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_RenderPresent(renderer); + SDL_Delay(1); + } + + /* free stuff */ + KW_Quit(gui); + TTF_CloseFont(font); + SDL_FreeSurface(set); + TTF_Quit(); + SDL_Quit(); + + return 0; +} diff --git a/examples/editbox/CMakeLists.txt b/examples/editbox/CMakeLists.txt index 48ea7ab..208f942 100644 --- a/examples/editbox/CMakeLists.txt +++ b/examples/editbox/CMakeLists.txt @@ -1,23 +1,23 @@ -project(editbox) -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -add_executable(editbox editbox.c tileset.png Fontin-Regular.ttf DejaVuSans.ttf) -target_link_libraries(editbox KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) - -add_custom_command(OUTPUT tileset.png - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png -) - -add_custom_command(OUTPUT Fontin-Regular.ttf - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf -) - -add_custom_command(OUTPUT DejaVuSans.ttf - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/DejaVuSans.ttf ${CMAKE_CURRENT_BINARY_DIR}/DejaVuSans.ttf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/DejaVuSans.ttf -) +project(editbox) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +add_executable(editbox editbox.c tileset.png Fontin-Regular.ttf DejaVuSans.ttf) +target_link_libraries(editbox KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + +add_custom_command(OUTPUT tileset.png + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png +) + +add_custom_command(OUTPUT Fontin-Regular.ttf + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf +) + +add_custom_command(OUTPUT DejaVuSans.ttf + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/DejaVuSans.ttf ${CMAKE_CURRENT_BINARY_DIR}/DejaVuSans.ttf + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/DejaVuSans.ttf +) diff --git a/examples/editbox/editbox.c b/examples/editbox/editbox.c index f692f0d..fb94c14 100644 --- a/examples/editbox/editbox.c +++ b/examples/editbox/editbox.c @@ -1,72 +1,72 @@ -#include "SDL.h" -#include "KW_gui.h" -#include "KW_button.h" -#include "KW_frame.h" -#include "KW_editbox.h" -#include "KW_label.h" -#include "KW_renderdriver_sdl2.h" - - -int main(int argc, char ** argv) { - SDL_Window * window; - SDL_Renderer * renderer; - KW_RenderDriver * driver; - KW_Surface * set; - KW_GUI * gui; - KW_Rect framegeom, editgeom, labelgeom, buttongeom; - KW_Widget * frame, * editbx, * label; - KW_Font * fontin, * dejavu; - - /* initialize window and renderer, and create a render driver */ - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 100, 100, 200, 1); - driver = KW_CreateSDL2RenderDriver(renderer, window); - - /* load tileset */ - set = KW_LoadSurface(driver, "tileset.png"); - - /* initialize gui */ - gui = KW_Init(driver, set); - fontin = KW_LoadFont(driver, "Fontin-Regular.ttf", 12); - dejavu = KW_LoadFont(driver, "DejaVuSans.ttf", 12); - KW_SetFont(gui, fontin); - - framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; - frame = KW_CreateFrame(gui, NULL, &framegeom); - buttongeom.x = 120, buttongeom.y = 110, buttongeom.w = 170, buttongeom.h = 30; - KW_CreateButton(gui, frame, "Friendship? Again?!", &buttongeom); - - framegeom.w -= 20; framegeom.h = 100; - editgeom.x = 120, editgeom.y = 20, editgeom.w = 150, editgeom.h = 30; - labelgeom.x = 10, labelgeom.y = 20, labelgeom.w = 110, labelgeom.h = 30; - frame = KW_CreateFrame(gui, frame, &framegeom); - editbx = KW_CreateEditbox(gui, frame, "Editbox #1", &editgeom); - KW_SetEditboxFont(editbx, dejavu); - label = KW_CreateLabel(gui, frame, "Type your destiny:", &labelgeom); - KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); - - editgeom.x = 120, editgeom.y = 50, editgeom.w = 150, editgeom.h = 30; - labelgeom.x = 10, labelgeom.y = 50, labelgeom.w = 110, labelgeom.h = 30; - editbx = KW_CreateEditbox(gui, frame, "Editbox #2", &editgeom); - - label = KW_CreateLabel(gui, frame, "Again:", &labelgeom); - KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); - - while (!SDL_QuitRequested()) { - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_RenderPresent(renderer); - SDL_Delay(1); - } - - /* free stuff */ - KW_Quit(gui); - TTF_CloseFont(fontin); - TTF_CloseFont(dejavu); - SDL_FreeSurface(set); - TTF_Quit(); - SDL_Quit(); - - return 0; -} +#include "SDL.h" +#include "KW_gui.h" +#include "KW_button.h" +#include "SDL_image.h" +#include "KW_frame.h" +#include "KW_editbox.h" +#include "KW_label.h" + + +int main(int argc, char ** argv) { + SDL_Window * window; + SDL_Renderer * renderer; + SDL_Surface * set; + KW_GUI * gui; + SDL_Rect framegeom, editgeom, labelgeom, buttongeom; + KW_Widget * frame, * editbx, * label; + TTF_Font * fontin, * dejavu; + +/* initialize window and renderer */ + SDL_Init(SDL_INIT_EVERYTHING); + SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 100, 100, 200, 1); + TTF_Init(); + + /* load tileset */ + + set = IMG_Load_RW(SDL_RWFromFile("tileset.png", "r"), SDL_TRUE); + + /* initialize gui */ + gui = KW_Init(renderer, set); + fontin = TTF_OpenFontRW(SDL_RWFromFile("Fontin-Regular.ttf", "r"), SDL_TRUE, 12); + dejavu = TTF_OpenFontRW(SDL_RWFromFile("DejaVuSans.ttf", "r"), SDL_TRUE, 11); + KW_SetFont(gui, fontin); + + framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; + frame = KW_CreateFrame(gui, NULL, &framegeom); + buttongeom.x = 120, buttongeom.y = 110, buttongeom.w = 170, buttongeom.h = 30; + KW_CreateButton(gui, frame, "Friendship? Again?!", &buttongeom); + + framegeom.w -= 20; framegeom.h = 100; + editgeom.x = 120, editgeom.y = 20, editgeom.w = 150, editgeom.h = 30; + labelgeom.x = 10, labelgeom.y = 20, labelgeom.w = 110, labelgeom.h = 30; + frame = KW_CreateFrame(gui, frame, &framegeom); + editbx = KW_CreateEditbox(gui, frame, "Editbox #1", &editgeom); + KW_SetEditboxFont(editbx, dejavu); + label = KW_CreateLabel(gui, frame, "Type your destiny:", &labelgeom); + KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); + + editgeom.x = 120, editgeom.y = 50, editgeom.w = 150, editgeom.h = 30; + labelgeom.x = 10, labelgeom.y = 50, labelgeom.w = 110, labelgeom.h = 30; + editbx = KW_CreateEditbox(gui, frame, "Editbox #2", &editgeom); + + label = KW_CreateLabel(gui, frame, "Again:", &labelgeom); + KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); + + while (!SDL_QuitRequested()) { + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_RenderPresent(renderer); + SDL_Delay(1); + } + + /* free stuff */ + KW_Quit(gui); + TTF_CloseFont(fontin); + TTF_CloseFont(dejavu); + SDL_FreeSurface(set); + TTF_Quit(); + SDL_Quit(); + + return 0; +} diff --git a/examples/fonts/COPYING b/examples/fonts/COPYING index 4565164..e894e66 100644 --- a/examples/fonts/COPYING +++ b/examples/fonts/COPYING @@ -1,5 +1,5 @@ -Fonts that starts with the name Fontin-* are under the following EULA: http://www.exljbris.com/eula.html -SourceSansPro-Semibold.ttf is under the following license: http://scripts.sil.org/OFL (SIL Open Font License) -DejaVuSans.ttf is under the this license: http://dejavu-fonts.org/wiki/License - -Before copying them, read their licensing please. +Fonts that starts with the name Fontin-* are under the following EULA: http://www.exljbris.com/eula.html +SourceSansPro-Semibold.ttf is under the following license: http://scripts.sil.org/OFL (SIL Open Font License) +DejaVuSans.ttf is under the this license: http://dejavu-fonts.org/wiki/License + +Before copying them, read their licensing please. diff --git a/examples/frame-family/CMakeLists.txt b/examples/frame-family/CMakeLists.txt index 9737ff0..cde09c1 100644 --- a/examples/frame-family/CMakeLists.txt +++ b/examples/frame-family/CMakeLists.txt @@ -1,19 +1,19 @@ -project(frame-family) -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -add_executable(frame-family frame-family.c tileset.png Fontin-Regular.ttf) -target_link_libraries(frame-family KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) - -add_custom_command(OUTPUT tileset.png - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png -) - -add_custom_command(OUTPUT Fontin-Regular.ttf - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf -) +project(frame-family) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +add_executable(frame-family frame-family.c tileset.png Fontin-Regular.ttf) +target_link_libraries(frame-family KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + +add_custom_command(OUTPUT tileset.png + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png +) + +add_custom_command(OUTPUT Fontin-Regular.ttf + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf +) \ No newline at end of file diff --git a/examples/frame-family/frame-family.c b/examples/frame-family/frame-family.c index ccbc123..05b5169 100644 --- a/examples/frame-family/frame-family.c +++ b/examples/frame-family/frame-family.c @@ -1,57 +1,56 @@ -#include "SDL.h" -#include "KW_gui.h" -#include "KW_button.h" -#include "KW_renderdriver_sdl2.h" - -int main(int argc, char ** argv) { - - /* initialize window and renderer */ - KW_RenderDriver * driver; - SDL_Window * window; - SDL_Renderer * renderer; - KW_Surface * set; - KW_GUI * gui; - KW_Font * font; - KW_Rect framegeom, labelgeom; - KW_Widget * frame; - int i = 0; - - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 100, 100, 100, 1); - driver = KW_CreateSDL2RenderDriver(renderer, window); - /* load tileset */ - - set = KW_LoadSurface(driver, "tileset.png"); - - /* initialize gui */ - gui = KW_Init(driver, set); - font = KW_LoadFont(driver, "Fontin-Regular.ttf", 12); - KW_SetFont(gui, font); - - - framegeom.x = 10, framegeom.y = 10, framegeom.w = 160, framegeom.h = 120; - labelgeom = framegeom; labelgeom.x = labelgeom.y = 0; - - /* create 10 frames and 10 labels */ - frame = NULL; - for (i = 0; i < 10; i++) { - frame = KW_CreateButton(gui, frame, "Yay", &framegeom); - } - - while (!SDL_QuitRequested()) { - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_RenderPresent(renderer); - SDL_Delay(1); - } - - /* free stuff */ - KW_Quit(gui); - TTF_CloseFont(font); - SDL_FreeSurface(set); - TTF_Quit(); - SDL_Quit(); - - return 0; -} +#include "SDL.h" +#include "KW_gui.h" +#include "KW_button.h" +#include "SDL_image.h" + +int main(int argc, char ** argv) { + + /* initialize window and renderer */ + SDL_Window * window; + SDL_Renderer * renderer; + SDL_Surface * set; + KW_GUI * gui; + TTF_Font * font; + SDL_Rect framegeom, labelgeom; + KW_Widget * frame; + int i = 0; + + SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); + SDL_Init(SDL_INIT_EVERYTHING); + TTF_Init(); + + /* load tileset */ + + set = IMG_Load("tileset.png"); + + /* initialize gui */ + gui = KW_Init(renderer, set); + font = TTF_OpenFont("Fontin-Regular.ttf", 12); + KW_SetFont(gui, font); + + + framegeom.x = 10, framegeom.y = 10, framegeom.w = 160, framegeom.h = 120; + labelgeom = framegeom; labelgeom.x = labelgeom.y = 0; + + /* create 10 frames and 10 labels */ + frame = NULL; + for (i = 0; i < 10; i++) { + frame = KW_CreateButton(gui, frame, "Yay", &framegeom); + } + while (!SDL_QuitRequested()) { + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_RenderPresent(renderer); + SDL_Delay(1); + } + + /* free stuff */ + KW_Quit(gui); + TTF_CloseFont(font); + SDL_FreeSurface(set); + TTF_Quit(); + SDL_Quit(); + + return 0; +} diff --git a/examples/playground/CMakeLists.txt b/examples/playground/CMakeLists.txt index eab25cd..dfa38e6 100644 --- a/examples/playground/CMakeLists.txt +++ b/examples/playground/CMakeLists.txt @@ -1,20 +1,20 @@ -project(playground) -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -# build a playground exe -add_executable(playground playground.c tileset.png Fontin-Regular.ttf) -target_link_libraries(playground KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) - -add_custom_command(OUTPUT tileset.png - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png -) - -add_custom_command(OUTPUT Fontin-Regular.ttf - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf -) +project(playground) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +# build a playground exe +add_executable(playground playground.c tileset.png Fontin-Regular.ttf) +target_link_libraries(playground KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + +add_custom_command(OUTPUT tileset.png + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png ${CMAKE_CURRENT_BINARY_DIR}/tileset.png + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/tileset.png +) + +add_custom_command(OUTPUT Fontin-Regular.ttf + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf ${CMAKE_CURRENT_BINARY_DIR}/Fontin-Regular.ttf + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/Fontin-Regular.ttf +) \ No newline at end of file diff --git a/examples/playground/playground.c b/examples/playground/playground.c index bd5a1f3..b1b0380 100644 --- a/examples/playground/playground.c +++ b/examples/playground/playground.c @@ -1,48 +1,52 @@ -#include "KW_gui.h" -#include "KW_frame.h" -#include "KW_label.h" -#include "KW_renderdriver_sdl2.h" - -int main(int argc, char ** argv) { - /* init SDL and SDL_ttf */ - KW_RenderDriver * driver; - SDL_Renderer * renderer; - SDL_Window * window; - KW_Surface * set; - KW_GUI * gui; - KW_Font * font; - KW_Widget * frame, * l; - KW_Rect geometry, c; - - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 100, 100, 100, 1); - driver = KW_CreateSDL2RenderDriver(renderer, window); - - /* load tileset surface */ - set = KW_LoadSurface(driver, "tileset.png"); - - /* load font */ - font = KW_LoadFont(driver, "Fontin-Regular.ttf", 12); - - /* init KiWi */ - gui = KW_Init(driver, set); - KW_SetFont(gui, font); - /* create a frame and a label on top of it. */ - geometry.x = geometry.y = 0; geometry.w = 320; geometry.h = 240; - frame = KW_CreateFrame(gui, NULL, &geometry); - l = KW_CreateLabel(gui, frame, "Label with an icon :)", &geometry); - c.x = 0; c.y = 48; c.w = 24; c.h = 24; - KW_SetLabelIcon(l, &c); - - while (!SDL_QuitRequested()) { - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_Delay(1); - SDL_RenderPresent(renderer); - } - KW_Quit(gui); - KW_ReleaseSurface(driver, set); - - return 0; -} +#include "SDL.h" +#include "SDL_ttf.h" +#include "SDL_image.h" +#include "KW_gui.h" +#include "KW_frame.h" +#include "KW_label.h" + +int main(int argc, char ** argv) { + /* init SDL and SDL_ttf */ + SDL_Renderer * renderer; + SDL_Window * window; + SDL_Surface * set; + KW_GUI * gui; + TTF_Font * font; + KW_Widget * frame, * l; + SDL_Rect geometry, c; + + SDL_Init(SDL_INIT_EVERYTHING); + SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 100, 100, 100, 1); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + + TTF_Init(); + + /* load tileset surface */ + + set = IMG_Load("tileset.png"); + + /* load font */ + font = TTF_OpenFont("Fontin-Regular.ttf", 12); + + /* init KiWi */ + gui = KW_Init(renderer, set); + KW_SetFont(gui, font); + /* create a frame and a label on top of it. */ + geometry.x = geometry.y = 0; geometry.w = 320; geometry.h = 240; + frame = KW_CreateFrame(gui, NULL, &geometry); + l = KW_CreateLabel(gui, frame, "Label with an icon :)", &geometry); + c.x = 0; c.y = 48; c.w = 24; c.h = 24; + KW_SetLabelIcon(l, &c); + + while (!SDL_QuitRequested()) { + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_Delay(1); + SDL_RenderPresent(renderer); + } + KW_Quit(gui); + SDL_FreeSurface(set); + + return 0; +} diff --git a/examples/scrollbox/CMakeLists.txt b/examples/scrollbox/CMakeLists.txt index 4ee66ce..81ed9de 100644 --- a/examples/scrollbox/CMakeLists.txt +++ b/examples/scrollbox/CMakeLists.txt @@ -1,23 +1,23 @@ -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") -set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") - -add_executable(scrollbox scrollbox.c ${TILESETS} ${FONTS}) -target_link_libraries(scrollbox KiWi ${SDL2_LIBRARIES} ${SDL2MAIN_LIBRARY} ${SDL2_IMAGE_LIBRARIES}) -foreach(TILESET ${TILESETS}) - add_custom_command(OUTPUT ${TILESET} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} - ) -endforeach(TILESET ${TILESETS}) - -foreach(FONT ${FONTS}) - add_custom_command(OUTPUT ${FONT} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} - ) -endforeach(FONT ${FONTS}) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") +set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") + +add_executable(scrollbox scrollbox.c ${TILESETS} ${FONTS}) +target_link_libraries(scrollbox KiWi ${SDL2_LIBRARIES} ${SDL2MAIN_LIBRARY} ${SDL2_IMAGE_LIBRARIES}) +foreach(TILESET ${TILESETS}) + add_custom_command(OUTPUT ${TILESET} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} + ) +endforeach(TILESET ${TILESETS}) + +foreach(FONT ${FONTS}) + add_custom_command(OUTPUT ${FONT} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} + ) +endforeach(FONT ${FONTS}) diff --git a/examples/scrollbox/scrollbox.c b/examples/scrollbox/scrollbox.c index 5b56492..e7a47e4 100644 --- a/examples/scrollbox/scrollbox.c +++ b/examples/scrollbox/scrollbox.c @@ -1,105 +1,105 @@ -#include "SDL.h" -#include "KW_gui.h" -#include "KW_button.h" -#include "KW_scrollbox.h" -#include "SDL_image.h" - -int dragmode = 0; - -void DragStart(KW_Widget * widget, int x, int y) { - SDL_Rect g; - KW_GetWidgetAbsoluteGeometry(widget, &g); - if (x> g.x + g.w - 40 && y > g.y + g.h -40) dragmode = 1; - else dragmode = 0; -} - -void DragStop(KW_Widget * widget, int x, int y) { -} - -void Drag(KW_Widget * widget, int x, int y, int xrel, int yrel) { - SDL_Rect g; - KW_GetWidgetGeometry(widget, &g); - if (dragmode == 1) { - g.w += xrel; - g.h += yrel; - } else { - g.x += xrel; - g.y += yrel; - } - KW_SetWidgetGeometry(widget, &g); -} - -int main(int argc, char ** argv) { - SDL_Window * window; - SDL_Renderer * renderer; - SDL_Surface * set; - KW_GUI * gui; - TTF_Font * font; - SDL_Rect geometry = {0, 0, 320, 240}; - KW_Widget * frame, * button; - int i; - SDL_Event ev; - - /* initialize SDL */ - SDL_Init(SDL_INIT_EVERYTHING); - - -#if defined(ANDROID) - /* enjoy all the screen size on android */ - i = SDL_GetNumVideoDisplays(); - if (i < 1) exit(1); - SDL_GetDisplayBounds(0, &geometry); -#endif - SDL_CreateWindowAndRenderer(geometry.w, geometry.h, SDL_WINDOW_RESIZABLE, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 100, 200, 100, 1); - TTF_Init(); - - /* load tileset */ - set = IMG_Load("tileset.png"); - - /* initialize gui */ - gui = KW_Init(renderer, set); - font = TTF_OpenFont("SourceSansPro-Semibold.ttf", 12); - TTF_SetFontHinting(font, TTF_HINTING_NONE); - KW_SetFont(gui, font); - - geometry.x = geometry.w * 0.0625; geometry.y = geometry.h * .0625; geometry.w *= .875f; geometry.h *= .875; - frame = KW_CreateScrollbox(gui, NULL, &geometry); - KW_AddWidgetDragStartHandler(frame, DragStart); - KW_AddWidgetDragHandler(frame, Drag); - KW_AddWidgetDragStopHandler(frame, DragStop); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - - geometry.x = 10; geometry.y = 0; geometry.h = 40; geometry.w = 230; - - for (i = 0; i < 5; i++) { - button = KW_CreateButton(gui, frame, "Drag me, resize me.", &geometry); - KW_AddWidgetDragStartHandler(button, DragStart); - KW_AddWidgetDragHandler(button, Drag); - KW_AddWidgetDragStopHandler(button, DragStop); - geometry.y += geometry.h; - } - - /* create another parent frame */ - while (!SDL_QuitRequested()) { - while (SDL_PollEvent(&ev)) { - if (ev.type == SDL_WINDOWEVENT && ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - geometry.w = ev.window.data1; - geometry.h = ev.window.data2; - geometry.x = geometry.w * 0.0625; geometry.y = geometry.h * .0625; geometry.w *= .875f; geometry.h *= .875; - KW_SetWidgetGeometry(frame, &geometry); - } - } - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_RenderPresent(renderer); - SDL_Delay(1); - } - TTF_CloseFont(font); - TTF_Quit(); - KW_Quit(gui); - SDL_FreeSurface(set); - SDL_Quit(); - - return 0; -} +#include "SDL.h" +#include "KW_gui.h" +#include "KW_button.h" +#include "KW_scrollbox.h" +#include "SDL_image.h" + +int dragmode = 0; + +void DragStart(KW_Widget * widget, int x, int y) { + SDL_Rect g; + KW_GetWidgetAbsoluteGeometry(widget, &g); + if (x> g.x + g.w - 40 && y > g.y + g.h -40) dragmode = 1; + else dragmode = 0; +} + +void DragStop(KW_Widget * widget, int x, int y) { +} + +void Drag(KW_Widget * widget, int x, int y, int xrel, int yrel) { + SDL_Rect g; + KW_GetWidgetGeometry(widget, &g); + if (dragmode == 1) { + g.w += xrel; + g.h += yrel; + } else { + g.x += xrel; + g.y += yrel; + } + KW_SetWidgetGeometry(widget, &g); +} + +int main(int argc, char ** argv) { + SDL_Window * window; + SDL_Renderer * renderer; + SDL_Surface * set; + KW_GUI * gui; + TTF_Font * font; + SDL_Rect geometry = {0, 0, 320, 240}; + KW_Widget * frame, * button; + int i; + SDL_Event ev; + + /* initialize SDL */ + SDL_Init(SDL_INIT_EVERYTHING); + + +#if defined(ANDROID) + /* enjoy all the screen size on android */ + i = SDL_GetNumVideoDisplays(); + if (i < 1) exit(1); + SDL_GetDisplayBounds(0, &geometry); +#endif + SDL_CreateWindowAndRenderer(geometry.w, geometry.h, SDL_WINDOW_RESIZABLE, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 100, 200, 100, 1); + TTF_Init(); + + /* load tileset */ + set = IMG_Load("tileset.png"); + + /* initialize gui */ + gui = KW_Init(renderer, set); + font = TTF_OpenFont("SourceSansPro-Semibold.ttf", 12); + TTF_SetFontHinting(font, TTF_HINTING_NONE); + KW_SetFont(gui, font); + + geometry.x = geometry.w * 0.0625; geometry.y = geometry.h * .0625; geometry.w *= .875f; geometry.h *= .875; + frame = KW_CreateScrollbox(gui, NULL, &geometry); + KW_AddWidgetDragStartHandler(frame, DragStart); + KW_AddWidgetDragHandler(frame, Drag); + KW_AddWidgetDragStopHandler(frame, DragStop); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + + geometry.x = 10; geometry.y = 0; geometry.h = 40; geometry.w = 230; + + for (i = 0; i < 5; i++) { + button = KW_CreateButton(gui, frame, "Drag me, resize me.", &geometry); + KW_AddWidgetDragStartHandler(button, DragStart); + KW_AddWidgetDragHandler(button, Drag); + KW_AddWidgetDragStopHandler(button, DragStop); + geometry.y += geometry.h; + } + + /* create another parent frame */ + while (!SDL_QuitRequested()) { + while (SDL_PollEvent(&ev)) { + if (ev.type == SDL_WINDOWEVENT && ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + geometry.w = ev.window.data1; + geometry.h = ev.window.data2; + geometry.x = geometry.w * 0.0625; geometry.y = geometry.h * .0625; geometry.w *= .875f; geometry.h *= .875; + KW_SetWidgetGeometry(frame, &geometry); + } + } + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_RenderPresent(renderer); + SDL_Delay(1); + } + TTF_CloseFont(font); + TTF_Quit(); + KW_Quit(gui); + SDL_FreeSurface(set); + SDL_Quit(); + + return 0; +} diff --git a/examples/styleswitcher/CMakeLists.txt b/examples/styleswitcher/CMakeLists.txt index e9515e2..93597ec 100644 --- a/examples/styleswitcher/CMakeLists.txt +++ b/examples/styleswitcher/CMakeLists.txt @@ -1,24 +1,24 @@ -project(styleswitcher) -cmake_minimum_required(VERSION 2.8) - -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) - -set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") -set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") - -add_executable(styleswitcher styleswitcher.c ${TILESETS} ${FONTS}) -target_link_libraries(styleswitcher KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) -foreach(TILESET ${TILESETS}) - add_custom_command(OUTPUT ${TILESET} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} - ) -endforeach(TILESET ${TILESETS}) - -foreach(FONT ${FONTS}) - add_custom_command(OUTPUT ${FONT} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} - ) -endforeach(FONT ${FONTS}) +project(styleswitcher) +cmake_minimum_required(VERSION 2.8) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) + +set(TILESETS "tileset.png;tileset-alloy.png;tileset-futterpedia.png;tileset-flat.png") +set(FONTS "Fontin-Regular.ttf;DejaVuSans.ttf;SourceSansPro-Semibold.ttf") + +add_executable(styleswitcher styleswitcher.c ${TILESETS} ${FONTS}) +target_link_libraries(styleswitcher KiWi ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) +foreach(TILESET ${TILESETS}) + add_custom_command(OUTPUT ${TILESET} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} ${CMAKE_CURRENT_BINARY_DIR}/${TILESET} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../tileset/${TILESET} + ) +endforeach(TILESET ${TILESETS}) + +foreach(FONT ${FONTS}) + add_custom_command(OUTPUT ${FONT} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} ${CMAKE_CURRENT_BINARY_DIR}/${FONT} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../fonts/${FONT} + ) +endforeach(FONT ${FONTS}) diff --git a/examples/styleswitcher/styleswitcher.c b/examples/styleswitcher/styleswitcher.c index da9696b..c73313b 100644 --- a/examples/styleswitcher/styleswitcher.c +++ b/examples/styleswitcher/styleswitcher.c @@ -1,155 +1,155 @@ -#include "SDL.h" -#include "KW_gui.h" -#include "KW_button.h" -#include "KW_frame.h" -#include "KW_editbox.h" -#include "KW_label.h" -#include "SDL_image.h" - -SDL_Surface * setalloy; -SDL_Surface * setfutter; -SDL_Surface * setflat; -SDL_Surface * set; - -TTF_Font * fontin; -TTF_Font * sourcepro; -SDL_bool quit = SDL_FALSE; - -void kthxbaiClicked(KW_Widget * widget, int b) { - quit = SDL_TRUE; -} - -void SwitchFlatClicked(KW_Widget * widget, int b) { - KW_GUI * gui = KW_GetGUI(widget); - SDL_Renderer * renderer = KW_GetRenderer(gui); - KW_SetFont(gui, sourcepro); - SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); - KW_SetTilesetSurface(gui, setflat); -} - -void SwitchAlloyClicked(KW_Widget * widget, int b) { - KW_GUI * gui = KW_GetGUI(widget); - SDL_Renderer * renderer = KW_GetRenderer(gui); - KW_SetFont(gui, sourcepro); - SDL_SetRenderDrawColor(renderer, 64, 67, 70, 1); - KW_SetTilesetSurface(gui, setalloy); -} - -void SwitchNormalClicked(KW_Widget * widget, int b) { - KW_GUI * gui = KW_GetGUI(widget); - SDL_Renderer * renderer = KW_GetRenderer(gui); - KW_SetFont(gui, fontin); - SDL_SetRenderDrawColor(renderer, 100, 100, 200, 1); - KW_SetTilesetSurface(gui, set); -} - -void SwitchFutterClicked(KW_Widget * widget, int b) { - KW_GUI * gui = KW_GetGUI(widget); - SDL_Renderer * renderer = KW_GetRenderer(gui); - KW_SetFont(gui, fontin); - SDL_SetRenderDrawColor(renderer, 118, 152, 162, 1); - KW_SetTilesetSurface(gui, setfutter); -} - -int main(int argc, char ** argv) { - SDL_Window * window; - SDL_Renderer * renderer; - KW_GUI * gui; - TTF_Font * dejavu; - SDL_Rect framegeom, editgeom, labelgeom, buttongeom; - KW_Widget * editbx, * label, * button, * kthxbai, * frame, * buttonsframe; - int hinting; - - /* initialize window and renderer */ - SDL_Init(SDL_INIT_EVERYTHING); - SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); - SDL_SetRenderDrawColor(renderer, 118, 152, 162, 1); - TTF_Init(); - - /* load tilesets */ - setalloy = IMG_Load_RW(SDL_RWFromFile("tileset-alloy.png", "r"), SDL_TRUE); - setfutter = IMG_Load_RW(SDL_RWFromFile("tileset-futterpedia.png", "r"), SDL_TRUE); - setflat = IMG_Load_RW(SDL_RWFromFile("tileset-flat.png", "r"), SDL_TRUE); - set = IMG_Load_RW(SDL_RWFromFile("tileset.png", "r"), SDL_TRUE); - - - /* initialize gui */ - gui = KW_Init(renderer, setfutter); - fontin = TTF_OpenFontRW(SDL_RWFromFile("Fontin-Regular.ttf", "r"), SDL_TRUE, 12); - sourcepro = TTF_OpenFontRW(SDL_RWFromFile("SourceSansPro-Semibold.ttf", "r"), SDL_TRUE, 12); - dejavu = TTF_OpenFontRW(SDL_RWFromFile("DejaVuSans.ttf", "r"), SDL_TRUE, 11); - - hinting = TTF_HINTING_NONE; - TTF_SetFontHinting(fontin, hinting); - TTF_SetFontHinting(sourcepro, hinting); - TTF_SetFontHinting(dejavu, hinting); - KW_SetFont(gui, fontin); - - /* top frame */ - framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; - frame = KW_CreateFrame(gui, NULL, &framegeom); - - /* buttons frame */ - framegeom.x = 10, framegeom.y = 160, framegeom.w = 280, framegeom.h = 48; - buttonsframe = KW_CreateFrame(gui, frame, &framegeom); - - /* buttons */ - button = NULL; - buttongeom.x = 10, buttongeom.y = 8, buttongeom.w = 32, buttongeom.h = 32; - button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); - KW_SetWidgetTilesetSurface(button, set); - KW_AddWidgetMouseDownHandler(button, SwitchNormalClicked); - - buttongeom.x += 290/4; - button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); - KW_SetWidgetTilesetSurface(button, setalloy); - KW_AddWidgetMouseDownHandler(button, SwitchAlloyClicked); - - buttongeom.x += 290/4; - button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); - KW_SetWidgetTilesetSurface(button, setfutter); - KW_AddWidgetMouseDownHandler(button, SwitchFutterClicked); - - buttongeom.x += 290/4; - button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); - KW_SetWidgetTilesetSurface(button, setflat); - KW_AddWidgetMouseDownHandler(button, SwitchFlatClicked); - - /* reset framegeom */ - framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; - framegeom.w -= 20; framegeom.h = 100; - - /* create the editbox frames */ - editgeom.x = 120, editgeom.y = 20, editgeom.w = 150, editgeom.h = 35; - labelgeom.x = 10, labelgeom.y = 20, labelgeom.w = 110, labelgeom.h = 35; - frame = KW_CreateFrame(gui, frame, &framegeom); - editbx = KW_CreateEditbox(gui, frame, "βέβαιος (sure)", &editgeom); - KW_SetEditboxFont(editbx, dejavu); - label = KW_CreateLabel(gui, frame, "Can you do UTF-8?", &labelgeom); - KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); - - buttongeom = editgeom; - buttongeom.y = 60; buttongeom.h -= 10; - kthxbai = KW_CreateButton(gui, frame, "kthxbai", &buttongeom); - KW_AddWidgetMouseDownHandler(kthxbai, kthxbaiClicked); - - while (!SDL_QuitRequested() && !quit) { - SDL_RenderClear(renderer); - KW_Paint(gui); - SDL_RenderPresent(renderer); - SDL_Delay(1); - } - - /* free stuff */ - KW_Quit(gui); - TTF_CloseFont(fontin); - TTF_CloseFont(dejavu); - SDL_FreeSurface(set); - SDL_FreeSurface(setalloy); - SDL_FreeSurface(setflat); - SDL_FreeSurface(setfutter); - TTF_Quit(); - SDL_Quit(); - - return 0; -} +#include "SDL.h" +#include "KW_gui.h" +#include "KW_button.h" +#include "KW_frame.h" +#include "KW_editbox.h" +#include "KW_label.h" +#include "SDL_image.h" + +SDL_Surface * setalloy; +SDL_Surface * setfutter; +SDL_Surface * setflat; +SDL_Surface * set; + +TTF_Font * fontin; +TTF_Font * sourcepro; +SDL_bool quit = SDL_FALSE; + +void kthxbaiClicked(KW_Widget * widget, int b) { + quit = SDL_TRUE; +} + +void SwitchFlatClicked(KW_Widget * widget, int b) { + KW_GUI * gui = KW_GetGUI(widget); + SDL_Renderer * renderer = KW_GetRenderer(gui); + KW_SetFont(gui, sourcepro); + SDL_SetRenderDrawColor(renderer, 200, 100, 100, 1); + KW_SetTilesetSurface(gui, setflat); +} + +void SwitchAlloyClicked(KW_Widget * widget, int b) { + KW_GUI * gui = KW_GetGUI(widget); + SDL_Renderer * renderer = KW_GetRenderer(gui); + KW_SetFont(gui, sourcepro); + SDL_SetRenderDrawColor(renderer, 64, 67, 70, 1); + KW_SetTilesetSurface(gui, setalloy); +} + +void SwitchNormalClicked(KW_Widget * widget, int b) { + KW_GUI * gui = KW_GetGUI(widget); + SDL_Renderer * renderer = KW_GetRenderer(gui); + KW_SetFont(gui, fontin); + SDL_SetRenderDrawColor(renderer, 100, 100, 200, 1); + KW_SetTilesetSurface(gui, set); +} + +void SwitchFutterClicked(KW_Widget * widget, int b) { + KW_GUI * gui = KW_GetGUI(widget); + SDL_Renderer * renderer = KW_GetRenderer(gui); + KW_SetFont(gui, fontin); + SDL_SetRenderDrawColor(renderer, 118, 152, 162, 1); + KW_SetTilesetSurface(gui, setfutter); +} + +int main(int argc, char ** argv) { + SDL_Window * window; + SDL_Renderer * renderer; + KW_GUI * gui; + TTF_Font * dejavu; + SDL_Rect framegeom, editgeom, labelgeom, buttongeom; + KW_Widget * editbx, * label, * button, * kthxbai, * frame, * buttonsframe; + int hinting; + + /* initialize window and renderer */ + SDL_Init(SDL_INIT_EVERYTHING); + SDL_CreateWindowAndRenderer(320, 240, 0, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 118, 152, 162, 1); + TTF_Init(); + + /* load tilesets */ + setalloy = IMG_Load_RW(SDL_RWFromFile("tileset-alloy.png", "r"), SDL_TRUE); + setfutter = IMG_Load_RW(SDL_RWFromFile("tileset-futterpedia.png", "r"), SDL_TRUE); + setflat = IMG_Load_RW(SDL_RWFromFile("tileset-flat.png", "r"), SDL_TRUE); + set = IMG_Load_RW(SDL_RWFromFile("tileset.png", "r"), SDL_TRUE); + + + /* initialize gui */ + gui = KW_Init(renderer, setfutter); + fontin = TTF_OpenFontRW(SDL_RWFromFile("Fontin-Regular.ttf", "r"), SDL_TRUE, 12); + sourcepro = TTF_OpenFontRW(SDL_RWFromFile("SourceSansPro-Semibold.ttf", "r"), SDL_TRUE, 12); + dejavu = TTF_OpenFontRW(SDL_RWFromFile("DejaVuSans.ttf", "r"), SDL_TRUE, 11); + + hinting = TTF_HINTING_NONE; + TTF_SetFontHinting(fontin, hinting); + TTF_SetFontHinting(sourcepro, hinting); + TTF_SetFontHinting(dejavu, hinting); + KW_SetFont(gui, fontin); + + /* top frame */ + framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; + frame = KW_CreateFrame(gui, NULL, &framegeom); + + /* buttons frame */ + framegeom.x = 10, framegeom.y = 160, framegeom.w = 280, framegeom.h = 48; + buttonsframe = KW_CreateFrame(gui, frame, &framegeom); + + /* buttons */ + button = NULL; + buttongeom.x = 10, buttongeom.y = 8, buttongeom.w = 32, buttongeom.h = 32; + button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); + KW_SetWidgetTilesetSurface(button, set); + KW_AddWidgetMouseDownHandler(button, SwitchNormalClicked); + + buttongeom.x += 290/4; + button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); + KW_SetWidgetTilesetSurface(button, setalloy); + KW_AddWidgetMouseDownHandler(button, SwitchAlloyClicked); + + buttongeom.x += 290/4; + button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); + KW_SetWidgetTilesetSurface(button, setfutter); + KW_AddWidgetMouseDownHandler(button, SwitchFutterClicked); + + buttongeom.x += 290/4; + button = KW_CreateButton(gui, buttonsframe, "", &buttongeom); + KW_SetWidgetTilesetSurface(button, setflat); + KW_AddWidgetMouseDownHandler(button, SwitchFlatClicked); + + /* reset framegeom */ + framegeom.x = 10, framegeom.y = 10, framegeom.w = 300, framegeom.h = 220; + framegeom.w -= 20; framegeom.h = 100; + + /* create the editbox frames */ + editgeom.x = 120, editgeom.y = 20, editgeom.w = 150, editgeom.h = 35; + labelgeom.x = 10, labelgeom.y = 20, labelgeom.w = 110, labelgeom.h = 35; + frame = KW_CreateFrame(gui, frame, &framegeom); + editbx = KW_CreateEditbox(gui, frame, "βέβαιος (sure)", &editgeom); + KW_SetEditboxFont(editbx, dejavu); + label = KW_CreateLabel(gui, frame, "Can you do UTF-8?", &labelgeom); + KW_SetLabelAlignment(label, KW_LABEL_ALIGN_RIGHT, 0, KW_LABEL_ALIGN_MIDDLE, 0); + + buttongeom = editgeom; + buttongeom.y = 60; buttongeom.h -= 10; + kthxbai = KW_CreateButton(gui, frame, "kthxbai", &buttongeom); + KW_AddWidgetMouseDownHandler(kthxbai, kthxbaiClicked); + + while (!SDL_QuitRequested() && !quit) { + SDL_RenderClear(renderer); + KW_Paint(gui); + SDL_RenderPresent(renderer); + SDL_Delay(1); + } + + /* free stuff */ + KW_Quit(gui); + TTF_CloseFont(fontin); + TTF_CloseFont(dejavu); + SDL_FreeSurface(set); + SDL_FreeSurface(setalloy); + SDL_FreeSurface(setflat); + SDL_FreeSurface(setfutter); + TTF_Quit(); + SDL_Quit(); + + return 0; +} diff --git a/examples/tileset/README b/examples/tileset/README index 6572c67..e3116f3 100644 --- a/examples/tileset/README +++ b/examples/tileset/README @@ -1 +1 @@ -tileset-futterpedia is based on http://designshack.net/design/futterpedia +tileset-futterpedia is based on http://designshack.net/design/futterpedia diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 744b5d4..8511557 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,59 @@ +<<<<<<< HEAD +set(SDL2_BUILDING_LIBRARY TRUE) +find_package(SDL2 REQUIRED) +find_package(SDL2_ttf REQUIRED) +find_package(SDL2_image REQUIRED) + +set(API_HEADERS + KW_gui.h + KW_button.h + KW_editbox.h + KW_frame.h + KW_label.h + KW_macros.h + KW_tilerenderer.h + KW_widget.h + KW_scrollbox.h + KW_renderdriver_sdl2.h + KW_renderdriver.h +) + +set(LIB_SOURCES + KW_scrollbox_internal.c + KW_scrollbox.c + KW_editbox_internal.c + utf8.c + KW_editbox.c + KW_eventwatcher.c + KW_button.c + KW_label.c + KW_label_internal.c + KW_gui.c + KW_frame.c + KW_frame_internal.c + KW_tilerenderer.c + KW_widget.c + KW_widget_eventhandlers.c + KW_renderdriver.c + KW_renderdriver_sdl2.c +) + +include_directories(${SDL2_INCLUDE_DIR}) +add_library(KiWi SHARED ${LIB_SOURCES} ${API_HEADERS}) +target_link_libraries(KiWi ${SDL2_LIBRARIES} ${SDL2_TTF_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + +# Configure install stuff +install(TARGETS KiWi EXPORT KiWiTargets + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +install(FILES ${API_HEADERS} DESTINATION include/KiWi) +======= set(SDL2_BUILDING_LIBRARY TRUE) find_package(SDL2 REQUIRED) find_package(SDL2_ttf REQUIRED) -find_package(SDL2_image REQUIRED) set(API_HEADERS KW_gui.h @@ -11,35 +63,14 @@ set(API_HEADERS KW_label.h KW_macros.h KW_tilerenderer.h + KW_textrenderer.h KW_widget.h KW_scrollbox.h - KW_renderdriver_sdl2.h - KW_renderdriver.h -) - -set(LIB_SOURCES - KW_scrollbox_internal.c - KW_scrollbox.c - KW_editbox_internal.c - utf8.c - KW_editbox.c - KW_eventwatcher.c - KW_button.c - KW_label.c - KW_label_internal.c - KW_gui.c - KW_frame.c - KW_frame_internal.c - KW_tilerenderer.c - KW_widget.c - KW_widget_eventhandlers.c - KW_renderdriver.c - KW_renderdriver_sdl2.c ) include_directories(${SDL2_INCLUDE_DIR}) -add_library(KiWi SHARED ${LIB_SOURCES} ${API_HEADERS}) -target_link_libraries(KiWi ${SDL2_LIBRARIES} ${SDL2_TTF_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) +add_library(KiWi SHARED KW_scrollbox_internal.c KW_scrollbox.c KW_editbox_internal.c utf8.c KW_editbox.c KW_eventwatcher.c KW_button.c KW_textrenderer.c KW_label.c KW_label_internal.c KW_gui.c KW_frame.c KW_frame_internal.c KW_tilerenderer.c KW_widget.c KW_widget_eventhandlers.c) +target_link_libraries(KiWi ${SDL2_LIBRARIES} ${SDL2_TTF_LIBRARIES}) # Configure install stuff install(TARGETS KiWi EXPORT KiWiTargets @@ -49,3 +80,4 @@ install(TARGETS KiWi EXPORT KiWiTargets ) install(FILES ${API_HEADERS} DESTINATION include/KiWi) +>>>>>>> parent of c84a94b... Adding renderdriver to sources, changing sources to a variable diff --git a/src/KW_button.c b/src/KW_button.c index 26662b6..e3b5f52 100644 --- a/src/KW_button.c +++ b/src/KW_button.c @@ -1,128 +1,128 @@ -#include "KW_button.h" -#include "KW_button_internal.h" -#include "KW_label.h" -#include "KW_tilerenderer.h" -#include "KW_gui.h" - -KW_Button * AllocButton(); -void PaintButton(KW_Widget * widget); -void RenderButton(KW_Widget * widget); -void DestroyButton(KW_Widget * widget); -void ButtonGeometryChanged(KW_Widget * widget, const KW_Rect * newgeom, const KW_Rect * oldgeom); - -static void MouseOver(KW_Widget * widget) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - button->mouseover = SDL_TRUE; -} - - -static void MouseLeave(KW_Widget * widget) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - button->mouseover = SDL_FALSE; -} - -static void MousePress(KW_Widget * widget, int b) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - button->clicked = SDL_TRUE; -} - -static void MouseRelease(KW_Widget * widget, int b) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - button->clicked = SDL_FALSE; -} - - -KW_Widget * KW_CreateButton(KW_GUI * gui, KW_Widget * parent, const char * text, const KW_Rect * geometry) { - KW_Rect labelgeom; - KW_Widget * widget = NULL; - KW_Button * button = NULL; - labelgeom.x = TILESIZE; - labelgeom.y = TILESIZE; - labelgeom.w = geometry->w - TILESIZE * 2; - labelgeom.h = geometry->h - TILESIZE * 2; - - button = AllocButton(); - widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_BUTTON, geometry, PaintButton, DestroyButton, button); - button->labelwidget = KW_CreateLabel(gui, widget, text, &labelgeom); - KW_BlockWidgetInputEvents(button->labelwidget); - KW_AddWidgetMouseOverHandler(widget, MouseOver); - KW_AddWidgetMouseLeaveHandler(widget, MouseLeave); - KW_AddWidgetMouseDownHandler(widget, MousePress); - KW_AddWidgetMouseUpHandler(widget, MouseRelease); - KW_AddWidgetGeometryChangeHandler(widget, ButtonGeometryChanged); - RenderButton(widget); - return widget; -} - -/** internal stuff **/ - -void PaintButton(KW_Widget * widget) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - KW_Rect targetgeom; - KW_RenderDriver * renderer = KW_GetWidgetRenderer(widget); - /* don't draw frame if requested. */ - if (KW_QueryWidgetHint(widget, KW_WIDGETHINT_FRAMELESS) == KW_TRUE) - return; - - KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); - if (button->mouseover) - KW_RenderCopy(renderer, button->normal, NULL, &targetgeom); - else - KW_RenderCopy(renderer, button->over, NULL, &targetgeom); -} - -void RenderButton(KW_Widget * widget) { - KW_Rect targetgeom; - KW_Surface * tileset = KW_GetWidgetTilesetSurface(widget); - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); - if (button->normal != NULL) SDL_DestroyTexture(button->normal); - button->normal = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 3, 3, targetgeom.w, targetgeom.h); - if (button->over != NULL) SDL_DestroyTexture(button->over); - button->over = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 3, 0, targetgeom.w, targetgeom.h); -} - -void DestroyButton(KW_Widget * widget) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - SDL_DestroyTexture(button->over); - SDL_DestroyTexture(button->normal); - free(button); -} - -void ButtonGeometryChanged(KW_Widget * widget, const KW_Rect * newgeom, const KW_Rect * oldgeom) { - KW_Rect labelgeom; - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - - if (oldgeom->w != newgeom->w || oldgeom->h != newgeom->h) { - RenderButton(widget); - } - - labelgeom.x = TILESIZE; - labelgeom.y = TILESIZE; - labelgeom.w = newgeom->w - TILESIZE * 2; - labelgeom.h = newgeom->h - TILESIZE * 2; - KW_SetWidgetGeometry(button->labelwidget, &labelgeom); -} - - -KW_Button * AllocButton() { - KW_Button * button = calloc(sizeof(KW_Button), 1); - return button; -} - -void KW_SetButtonIcon(KW_Widget * widget, const KW_Rect * iconclip) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - KW_SetLabelIcon(button->labelwidget, iconclip); -} - -void KW_SetButtonText(KW_Widget * widget, const char * text) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - KW_SetLabelText(button->labelwidget, text); -} - - - -void KW_SetButtonFont(KW_Widget * widget, TTF_Font * font) { - KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); - KW_SetLabelFont(button->labelwidget, font); -} +#include "KW_button.h" +#include "KW_button_internal.h" +#include "KW_label.h" +#include "KW_tilerenderer.h" +#include "KW_gui.h" + +KW_Button * AllocButton(); +void PaintButton(KW_Widget * widget); +void RenderButton(KW_Widget * widget); +void DestroyButton(KW_Widget * widget); +void ButtonGeometryChanged(KW_Widget * widget, const SDL_Rect * newgeom, const SDL_Rect * oldgeom); + +static void MouseOver(KW_Widget * widget) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + button->mouseover = SDL_TRUE; +} + + +static void MouseLeave(KW_Widget * widget) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + button->mouseover = SDL_FALSE; +} + +static void MousePress(KW_Widget * widget, int b) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + button->clicked = SDL_TRUE; +} + +static void MouseRelease(KW_Widget * widget, int b) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + button->clicked = SDL_FALSE; +} + + +KW_Widget * KW_CreateButton(KW_GUI * gui, KW_Widget * parent, const char * text, const SDL_Rect * geometry) { + SDL_Rect labelgeom; + KW_Widget * widget = NULL; + KW_Button * button = NULL; + labelgeom.x = TILESIZE; + labelgeom.y = TILESIZE; + labelgeom.w = geometry->w - TILESIZE * 2; + labelgeom.h = geometry->h - TILESIZE * 2; + + button = AllocButton(); + widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_BUTTON, geometry, PaintButton, DestroyButton, button); + button->labelwidget = KW_CreateLabel(gui, widget, text, &labelgeom); + KW_BlockWidgetInputEvents(button->labelwidget); + KW_AddWidgetMouseOverHandler(widget, MouseOver); + KW_AddWidgetMouseLeaveHandler(widget, MouseLeave); + KW_AddWidgetMouseDownHandler(widget, MousePress); + KW_AddWidgetMouseUpHandler(widget, MouseRelease); + KW_AddWidgetGeometryChangeHandler(widget, ButtonGeometryChanged); + RenderButton(widget); + return widget; +} + +/** internal stuff **/ + +void PaintButton(KW_Widget * widget) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + SDL_Rect targetgeom; + SDL_Renderer * renderer = KW_GetWidgetRenderer(widget); + /* don't draw frame if requested. */ + if (KW_QueryWidgetHint(widget, KW_WIDGETHINT_FRAMELESS) == SDL_TRUE) + return; + + KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); + if (button->mouseover) + SDL_RenderCopy(renderer, button->normal, NULL, &targetgeom); + else + SDL_RenderCopy(renderer, button->over, NULL, &targetgeom); +} + +void RenderButton(KW_Widget * widget) { + SDL_Rect targetgeom; + SDL_Surface * tileset = KW_GetWidgetTilesetSurface(widget); + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); + if (button->normal != NULL) SDL_DestroyTexture(button->normal); + button->normal = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 3, 3, targetgeom.w, targetgeom.h); + if (button->over != NULL) SDL_DestroyTexture(button->over); + button->over = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 3, 0, targetgeom.w, targetgeom.h); +} + +void DestroyButton(KW_Widget * widget) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + SDL_DestroyTexture(button->over); + SDL_DestroyTexture(button->normal); + free(button); +} + +void ButtonGeometryChanged(KW_Widget * widget, const SDL_Rect * newgeom, const SDL_Rect * oldgeom) { + SDL_Rect labelgeom; + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + + if (oldgeom->w != newgeom->w || oldgeom->h != newgeom->h) { + RenderButton(widget); + } + + labelgeom.x = TILESIZE; + labelgeom.y = TILESIZE; + labelgeom.w = newgeom->w - TILESIZE * 2; + labelgeom.h = newgeom->h - TILESIZE * 2; + KW_SetWidgetGeometry(button->labelwidget, &labelgeom); +} + + +KW_Button * AllocButton() { + KW_Button * button = calloc(sizeof(KW_Button), 1); + return button; +} + +void KW_SetButtonIcon(KW_Widget * widget, const SDL_Rect * iconclip) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + KW_SetLabelIcon(button->labelwidget, iconclip); +} + +void KW_SetButtonText(KW_Widget * widget, const char * text) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + KW_SetLabelText(button->labelwidget, text); +} + + + +void KW_SetButtonFont(KW_Widget * widget, TTF_Font * font) { + KW_Button * button = KW_GetWidgetData(widget, KW_WIDGETTYPE_BUTTON); + KW_SetLabelFont(button->labelwidget, font); +} diff --git a/src/KW_button.h b/src/KW_button.h index 4324857..7bdb1f5 100644 --- a/src/KW_button.h +++ b/src/KW_button.h @@ -1,78 +1,78 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_BUTTON_H -#define KW_BUTTON_H -#include "KW_widget.h" -#include "SDL_ttf.h" - -/** - * \file KW_button.h - * - * Declares functions for creating and managing buttons - */ - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * \brief Creates a button widget. - * \details The button widget is a composite widget. It uses the second 3x3 tile block (next to the frame block) to render its lines. - * \param gui The KW_GUI instance that will hold this button. - * \param parent The parent widget of this button. - * \param text The text to print inside the button. - * \param geometry The geometry of this button. - * \return The button instance. - */ -extern DECLSPEC KW_Widget * KW_CreateButton(KW_GUI * gui, KW_Widget * parent, const char * text, const KW_Rect * geometry); - -/** - * \brief Sets the text being displayed in a button. - * \param text The new text to show. - */ -extern DECLSPEC void KW_SetButtonText(KW_Widget * button, const char * text); - -/** - * \brief Sets the icon being displayed in a button - * \param widget The button widget to show the icon. - * \param iconclip The area in the tileset to clip the icon from. Set to NULL - * to remove the icon. - */ -extern DECLSPEC void KW_SetButtonIcon(KW_Widget * widget, const KW_Rect * iconclip); - -/** - * \brief Changes the font of the button's text. - * \details Please note that you are responsible for managing the font memory and should free the previous font if its not required anymore. - * \param widget The button widget. - * \param font The font to assign to the button. - */ -extern DECLSPEC void KW_SetButtonFont(KW_Widget * button, TTF_Font * font); - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_BUTTON_H +#define KW_BUTTON_H +#include "KW_widget.h" +#include "SDL_ttf.h" + +/** + * \file KW_button.h + * + * Declares functions for creating and managing buttons + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * \brief Creates a button widget. + * \details The button widget is a composite widget. It uses the second 3x3 tile block (next to the frame block) to render its lines. + * \param gui The KW_GUI instance that will hold this button. + * \param parent The parent widget of this button. + * \param text The text to print inside the button. + * \param geometry The geometry of this button. + * \return The button instance. + */ +extern DECLSPEC KW_Widget * KW_CreateButton(KW_GUI * gui, KW_Widget * parent, const char * text, const SDL_Rect * geometry); + +/** + * \brief Sets the text being displayed in a button. + * \param text The new text to show. + */ +extern DECLSPEC void KW_SetButtonText(KW_Widget * button, const char * text); + +/** + * \brief Sets the icon being displayed in a button + * \param widget The button widget to show the icon. + * \param iconclip The area in the tileset to clip the icon from. Set to NULL + * to remove the icon. + */ +extern DECLSPEC void KW_SetButtonIcon(KW_Widget * widget, const SDL_Rect * iconclip); + +/** + * \brief Changes the font of the button's text. + * \details Please note that you are responsible for managing the font memory and should free the previous font if its not required anymore. + * \param widget The button widget. + * \param font The font to assign to the button. + */ +extern DECLSPEC void KW_SetButtonFont(KW_Widget * button, TTF_Font * font); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_button_internal.h b/src/KW_button_internal.h index 3b73392..9e243d2 100644 --- a/src/KW_button_internal.h +++ b/src/KW_button_internal.h @@ -1,15 +1,15 @@ -#ifndef KW_BUTTON_INTERNAL_H -#define KW_BUTTON_INTERNAL_H - -#include "KW_widget.h" - -typedef struct KW_Button { - KW_Widget * labelwidget; /* the label inside the button frame */ - KW_bool mouseover; - KW_bool clicked; - KW_Texture * normal; - KW_Texture * over; -} KW_Button; - - -#endif +#ifndef KW_BUTTON_INTERNAL_H +#define KW_BUTTON_INTERNAL_H + +#include "KW_widget.h" + +typedef struct KW_Button { + KW_Widget * labelwidget; /* the label inside the button frame */ + SDL_bool mouseover; + SDL_bool clicked; + SDL_Texture * normal; + SDL_Texture * over; +} KW_Button; + + +#endif diff --git a/src/KW_editbox.c b/src/KW_editbox.c index 996f9df..5ad2ebb 100644 --- a/src/KW_editbox.c +++ b/src/KW_editbox.c @@ -1,61 +1,61 @@ -#include "KW_editbox.h" -#include "KW_widget.h" -#include "KW_gui.h" -#include "KW_editbox_internal.h" - -/* public functions */ -KW_Widget * KW_CreateEditbox(KW_GUI * gui, KW_Widget * parent, const char * text, const KW_Rect * geometry) { - KW_Editbox * editbox = AllocEditbox(); - KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_EDITBOX, geometry, PaintEditbox, DestroyEditbox, editbox); - SDL_strlcat(editbox->text, text, 1024); - editbox->font = NULL; - editbox->widget = widget; - - KW_AddWidgetMouseOverHandler(widget, EditboxMouseOver); - KW_AddWidgetMouseLeaveHandler(widget, EditboxMouseLeave); - KW_AddWidgetMouseDownHandler(widget, EditboxMousePress); - KW_AddWidgetMouseUpHandler(widget, EditboxMouseRelease); - KW_AddWidgetFocusGainHandler(widget, EditboxFocusGain); - KW_AddWidgetFocusLoseHandler(widget, EditboxFocusLose); - KW_AddWidgetTextInputHandler(widget, EditboxTextInput); - KW_AddWidgetKeyDownHandler(widget, EditboxKeyDown); - - KW_AddGUIFontChangedHandler(gui, EditboxFontChanged, widget); - - RenderEditboxText(editbox); - AdjustCursor(editbox, SDL_strlen(text)); - return widget; -} - -unsigned int KW_GetEditboxCursorPosition(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - return editbox->cursor; -} - -KW_Font * KW_GetEditboxFont(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - return editbox->font == NULL ? KW_GetFont(KW_GetGUI(widget)) : editbox->font; -} - -const char * KW_GetEditboxText(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - return editbox->text; -} - -void KW_SetEditboxCursorPosition(KW_Widget * widget, unsigned int pos) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->cursor = pos; -} - -void KW_SetEditboxFont(KW_Widget * widget, KW_Font * font) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->font = font; - RenderEditboxText(editbox); - AdjustCursor(editbox, 1); -} - -void KW_SetEditboxText(KW_Widget * widget, const char * text) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - SDL_strlcat(editbox->text, text, 1024); - RenderEditboxText(editbox); -} +#include "KW_editbox.h" +#include "KW_widget.h" +#include "KW_gui.h" +#include "KW_editbox_internal.h" + +/* public functions */ +KW_Widget * KW_CreateEditbox(KW_GUI * gui, KW_Widget * parent, const char * text, const SDL_Rect * geometry) { + KW_Editbox * editbox = AllocEditbox(); + KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_EDITBOX, geometry, PaintEditbox, DestroyEditbox, editbox); + SDL_strlcat(editbox->text, text, 1024); + editbox->font = NULL; + editbox->widget = widget; + + KW_AddWidgetMouseOverHandler(widget, EditboxMouseOver); + KW_AddWidgetMouseLeaveHandler(widget, EditboxMouseLeave); + KW_AddWidgetMouseDownHandler(widget, EditboxMousePress); + KW_AddWidgetMouseUpHandler(widget, EditboxMouseRelease); + KW_AddWidgetFocusGainHandler(widget, EditboxFocusGain); + KW_AddWidgetFocusLoseHandler(widget, EditboxFocusLose); + KW_AddWidgetTextInputHandler(widget, EditboxTextInput); + KW_AddWidgetKeyDownHandler(widget, EditboxKeyDown); + + KW_AddGUIFontChangedHandler(gui, EditboxFontChanged, widget); + + RenderEditboxText(editbox); + AdjustCursor(editbox, SDL_strlen(text)); + return widget; +} + +unsigned int KW_GetEditboxCursorPosition(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + return editbox->cursor; +} + +TTF_Font * KW_GetEditboxFont(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + return editbox->font == NULL ? KW_GetFont(KW_GetGUI(widget)) : editbox->font; +} + +const char * KW_GetEditboxText(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + return editbox->text; +} + +void KW_SetEditboxCursorPosition(KW_Widget * widget, unsigned int pos) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->cursor = pos; +} + +void KW_SetEditboxFont(KW_Widget * widget, TTF_Font * font) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->font = font; + RenderEditboxText(editbox); + AdjustCursor(editbox, 1); +} + +void KW_SetEditboxText(KW_Widget * widget, const char * text) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + SDL_strlcat(editbox->text, text, 1024); + RenderEditboxText(editbox); +} diff --git a/src/KW_editbox.h b/src/KW_editbox.h index a84634f..ac512f8 100644 --- a/src/KW_editbox.h +++ b/src/KW_editbox.h @@ -1,49 +1,57 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_EDITBOX_H -#define KW_EDITBOX_H - -/** - * \file KW_editbox.h - * - * Defines functions related to creating and managing edit boxes - */ - -#include "KW_widget.h" -#include "SDL_ttf.h" - -extern DECLSPEC KW_Widget * KW_CreateEditbox(KW_GUI * gui, KW_Widget * parent, - const char * text, - const KW_Rect * geometry); - -extern DECLSPEC void KW_SetEditboxText(KW_Widget * widget, const char * text); -extern DECLSPEC const char * KW_GetEditboxText(KW_Widget * widget); -extern DECLSPEC void KW_SetEditboxCursorPosition(KW_Widget * widget, - unsigned int pos); -extern DECLSPEC unsigned int KW_GetEditboxCursorPosition(KW_Widget * widget); -extern DECLSPEC void KW_SetEditboxFont(KW_Widget * widget, KW_Font * font); -extern DECLSPEC KW_Font * KW_GetEditboxFont(KW_Widget * widget); - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_EDITBOX_H +#define KW_EDITBOX_H + +/** + * \file KW_editbox.h + * + * Defines functions related to creating and managing edit boxes + */ + +#include "KW_widget.h" +#include "SDL_ttf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern DECLSPEC KW_Widget * KW_CreateEditbox(KW_GUI * gui, KW_Widget * parent, + const char * text, + const SDL_Rect * geometry); + +extern DECLSPEC void KW_SetEditboxText(KW_Widget * widget, const char * text); +extern DECLSPEC const char * KW_GetEditboxText(KW_Widget * widget); +extern DECLSPEC void KW_SetEditboxCursorPosition(KW_Widget * widget, + unsigned int pos); +extern DECLSPEC unsigned int KW_GetEditboxCursorPosition(KW_Widget * widget); +extern DECLSPEC void KW_SetEditboxFont(KW_Widget * widget, TTF_Font * font); +extern DECLSPEC TTF_Font * KW_GetEditboxFont(KW_Widget * widget); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_editbox_internal.c b/src/KW_editbox_internal.c index ce76d71..5384aff 100644 --- a/src/KW_editbox_internal.c +++ b/src/KW_editbox_internal.c @@ -1,279 +1,282 @@ -#include "KW_editbox.h" -#include "KW_editbox_internal.h" -#include "KW_tilerenderer.h" -#include "utf8.h" - -/* private functions */ -void PaintEditbox(KW_Widget * widget) { - KW_Rect targetgeom; - KW_RenderDriver * renderer; - KW_Texture * tileset; - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - /* base column for tile rendering */ - int basec = 0; - if (editbox->mouseover || editbox->active) basec = 3; - if (editbox->clicked) basec = 0; - - KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); - - renderer = KW_GetWidgetRenderer(widget); - tileset = KW_GetWidgetTilesetTexture(widget); - - KW_RenderTileFrame(renderer, tileset, 6, basec, targetgeom.x, targetgeom.y, targetgeom.w, targetgeom.h); - - /* adjust target geom */ - targetgeom.x += TILESIZE; - targetgeom.y += TILESIZE; - targetgeom.w = targetgeom.w - TILESIZE * 2; - targetgeom.h = targetgeom.h - TILESIZE * 2; - - PaintEditboxText(editbox, &targetgeom); -} - -/* paints the editbox text */ -void PaintEditboxText(KW_Editbox * editbox, KW_Rect * _dst) { - KW_Rect dst = *_dst; /* destination rectangle */ - KW_Rect orig = dst; /* intended dst rectangle */ - KW_Rect src; /* text clipping */ - int cursorx; - - KW_RenderDriver * renderer = KW_GetWidgetRenderer(editbox->widget); - KW_Texture * tileset = KW_GetWidgetTilesetTexture(editbox->widget); - - /* query actual w and h */ - src.x = src.y = 0; src.w = editbox->textwidth; src.h = editbox->textheight; - - /* will paint label in the middle */ - dst.y = dst.y + dst.h / 2 - src.h / 2; - - /* clip bottom part (middle, top) */ - if (dst.y + src.h > orig.y + orig.h) src.h = orig.h + (orig.y - dst.y) - src.y; - - /* ajust text src rect and render cursor if active */ - cursorx = editbox->cursorx; - if (editbox->active) { - int adjust = editbox->cursoradjustx; - /* if the cursor is left to the clipping rectangle */ - if (cursorx < adjust) { - adjust = cursorx; - } - /* if the cursor is right of the clipping rectangle (dst.w or less) */ - else if (cursorx > adjust + dst.w) { - adjust = cursorx - dst.w; - cursorx = adjust; - } - - /* sets the clipping origin as calculated */ - src.x = adjust; - - /* save the adjust for next time */ - editbox->cursoradjustx = adjust; - - /* see if the clip rect is bigger than dst */ - if (src.w > dst.w) src.w = dst.w; - - /* see if clipping rect is bigger than total width, might have - * to adjust clipping origin */ - if ((src.x + src.w) > editbox->textwidth) { - src.x -= (src.x + src.w) - editbox->textwidth; - } - - /* basic checks */ - if (src.w < dst.w) dst.w = src.w; - if (src.h < dst.h) dst.h = src.h; - - /* render cursor *below* text */ - KW_RenderTileFill(renderer, tileset, 7, 7, dst.x + cursorx - src.x, dst.y, - TILESIZE, dst.h); - - /* render text */ - KW_RenderCopy(renderer, editbox->textrender, &src, &dst); - } else { - /* just the basic checks */ - if (src.w > dst.w) src.w = dst.w; - if (src.w < dst.w) dst.w = src.w; - if (src.h < dst.h) dst.h = src.h; - KW_RenderCopy(renderer, editbox->textrender, &src, &dst); - } -} - - -void RenderEditboxText(KW_Editbox * editbox) { - if (editbox->textrender != NULL) { - KW_ReleaseTexture(KW_GetWidgetRenderer(editbox->widget), editbox->textrender); - } - /* use our own font */ - editbox->textrender = KW_RenderText(KW_GetWidgetRenderer(editbox->widget), KW_GetEditboxFont(editbox->widget), - editbox->text, editbox->color, - TTF_STYLE_NORMAL); - - if (editbox->textrender != NULL) - SDL_QueryTexture(editbox->textrender, NULL, NULL, &(editbox->textwidth), - &(editbox->textheight)); - else - TTF_SizeUTF8(KW_GetEditboxFont(editbox->widget), "", &(editbox->textwidth), &(editbox->textheight)); -} - -KW_Editbox * AllocEditbox() { - KW_Editbox * editbox = calloc(sizeof(*editbox), 1); - return editbox; -} - -void DestroyEditbox(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - free(editbox); -} -void AdjustCursor(KW_Editbox * editbox, int cursormove) { - char save; - int len = SDL_strlen(editbox->text); - - /* adjust cursormove, don't let it over/underflow. */ - if (cursormove > 0) { - if (editbox->cursor + cursormove > len) { - cursormove = len - editbox->cursor; - } - } else if (cursormove < 0) { - if (-cursormove > editbox->cursor) { - cursormove = -editbox->cursor; - } - } - - /* now account for UTF-8 */ - if (cursormove > 0) { - /* its a UTF-8 sequence */ - while (cursormove-- > 0) { - (void)( - isutf(editbox->text[++(editbox->cursor)]) - || isutf(editbox->text[++(editbox->cursor)]) - || isutf(editbox->text[++(editbox->cursor)]) - || ++(editbox->cursor) - ); - } - } else if (cursormove < 0) { - while (cursormove++ < 0) { - (void)( - isutf(editbox->text[--(editbox->cursor)]) - || isutf(editbox->text[--(editbox->cursor)]) - || isutf(editbox->text[--(editbox->cursor)]) - || --(editbox->cursor) - ); - } - } - - /* recalculate cursor position */ - save = editbox->text[editbox->cursor]; - editbox->text[editbox->cursor] = '\0'; - TTF_SizeUTF8(KW_GetEditboxFont(editbox->widget), editbox->text, &editbox->cursorx, NULL); - editbox->text[editbox->cursor] = save; -} - -void TextBackspace(KW_Editbox * editbox) { - AdjustCursor(editbox, -1); - TextDelete(editbox); -} - -void TextDelete(KW_Editbox * editbox) { - int i = 0; - int len = SDL_strlen(editbox->text); - int seq = u8_seqlen(editbox->text[editbox->cursor]); - printf("seqlen is %d\n", seq); - for (i = editbox->cursor; i < len; i++) { - editbox->text[i] = editbox->text[i + seq]; - } - RenderEditboxText(editbox); -} - -/* KiWi callbacks */ -void EditboxKeyDown(KW_Widget * widget, SDL_Keycode key, SDL_Scancode scan) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - switch (scan) { - /* set up cursor states */ - case SDL_SCANCODE_LEFT: - AdjustCursor(editbox, -1); - break; - case SDL_SCANCODE_RIGHT: - AdjustCursor(editbox, 1); - break; - - case SDL_SCANCODE_BACKSPACE: - TextBackspace(editbox); - break; - - case SDL_SCANCODE_DELETE: - TextDelete(editbox); - break; - - case SDL_SCANCODE_HOME: - AdjustCursor(editbox, -u8_strlen(editbox->text)); - break; - - case SDL_SCANCODE_END: - AdjustCursor(editbox, u8_strlen(editbox->text)); - break; - - default: - break; - } -} - -void EditboxTextInput(KW_Widget * widget, const char * text) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - int i = 0, insertlen, textlen, cursoradjust; - - /* make room in the middle */ - i = editbox->cursor; - insertlen = SDL_strlen(text); - cursoradjust = insertlen; - textlen = SDL_strlen(editbox->text); - - for (i = textlen; i >= editbox->cursor && i > 0; i--) { - editbox->text[textlen + insertlen - (textlen - i)] = editbox->text[i]; - } - - for (i = 0; i < insertlen; i++) { - editbox->text[editbox->cursor + i] = text[i]; - } - - /* correct insertlen if its utf8 because AdjustCursor is in terms - * of perceived chars */ - cursoradjust = u8_strlen(text); - AdjustCursor(editbox, cursoradjust); - RenderEditboxText(editbox); -} - -void EditboxMouseOver(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->mouseover = SDL_TRUE; -} - -void EditboxMouseLeave(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->mouseover = SDL_FALSE; -} - -void EditboxMousePress(KW_Widget * widget, int b) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->clicked = SDL_TRUE; -} - -void EditboxMouseRelease(KW_Widget * widget, int b) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->clicked = SDL_FALSE; -} - -void EditboxFocusGain(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->active = SDL_TRUE; - SDL_StartTextInput(); -} - -void EditboxFocusLose(KW_Widget * widget) { - KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); - editbox->active = SDL_FALSE; - SDL_StopTextInput(); -} - -void EditboxFontChanged(KW_GUI * gui, void * priv, KW_Font * font) { - KW_Editbox * editbox = KW_GetWidgetData((KW_Widget*)priv, KW_WIDGETTYPE_EDITBOX); - RenderEditboxText(editbox); -} +#include "KW_editbox.h" +#include "KW_editbox_internal.h" +#include "KW_tilerenderer.h" +#include "KW_textrenderer.h" +#include "utf8.h" + +/* private functions */ +void PaintEditbox(KW_Widget * widget) { + SDL_Rect targetgeom; + SDL_Renderer * renderer; + SDL_Texture * tileset; + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + /* base column for tile rendering */ + int basec = 0; + if (editbox->mouseover || editbox->active) basec = 3; + if (editbox->clicked) basec = 0; + + + KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); + + renderer = KW_GetWidgetRenderer(widget); + tileset = KW_GetWidgetTilesetTexture(widget); + + KW_RenderTileFrame(renderer, tileset, 6, basec, targetgeom.x, targetgeom.y, targetgeom.w, targetgeom.h); + + /* adjust target geom */ + targetgeom.x += TILESIZE; + targetgeom.y += TILESIZE; + targetgeom.w = targetgeom.w - TILESIZE * 2; + targetgeom.h = targetgeom.h - TILESIZE * 2; + + PaintEditboxText(editbox, &targetgeom); +} + +/* paints the editbox text */ +void PaintEditboxText(KW_Editbox * editbox, SDL_Rect * _dst) { + SDL_Rect dst = *_dst; /* destination rectangle */ + SDL_Rect orig = dst; /* intended dst rectangle */ + SDL_Rect src; /* text clipping */ + int cursorx; + + SDL_Renderer * renderer = KW_GetWidgetRenderer(editbox->widget); + SDL_Texture * tileset = KW_GetWidgetTilesetTexture(editbox->widget); + + /* query actual w and h */ + src.x = src.y = 0; src.w = editbox->textwidth; src.h = editbox->textheight; + + /* will paint label in the middle */ + dst.y = dst.y + dst.h / 2 - src.h / 2; + + /* clip bottom part (middle, top) */ + if (dst.y + src.h > orig.y + orig.h) src.h = orig.h + (orig.y - dst.y) - src.y; + + /* ajust text src rect and render cursor if active */ + cursorx = editbox->cursorx; + if (editbox->active) { + int adjust = editbox->cursoradjustx; + /* if the cursor is left to the clipping rectangle */ + if (cursorx < adjust) { + adjust = cursorx; + } + /* if the cursor is right of the clipping rectangle (dst.w or less) */ + else if (cursorx > adjust + dst.w) { + adjust = cursorx - dst.w; + cursorx = adjust; + } + + /* sets the clipping origin as calculated */ + src.x = adjust; + + /* save the adjust for next time */ + editbox->cursoradjustx = adjust; + + /* see if the clip rect is bigger than dst */ + if (src.w > dst.w) src.w = dst.w; + + /* see if clipping rect is bigger than total width, might have + * to adjust clipping origin */ + if ((src.x + src.w) > editbox->textwidth) { + src.x -= (src.x + src.w) - editbox->textwidth; + } + + /* basic checks */ + if (src.w < dst.w) dst.w = src.w; + if (src.h < dst.h) dst.h = src.h; + + /* render cursor *below* text */ + KW_RenderTileFill(renderer, tileset, 7, 7, dst.x + cursorx - src.x, dst.y, + TILESIZE, dst.h); + + /* render text */ + SDL_RenderCopy(renderer, editbox->textrender, &src, &dst); + } else { + /* just the basic checks */ + if (src.w > dst.w) src.w = dst.w; + if (src.w < dst.w) dst.w = src.w; + if (src.h < dst.h) dst.h = src.h; + SDL_RenderCopy(renderer, editbox->textrender, &src, &dst); + } +} + + +void RenderEditboxText(KW_Editbox * editbox) { + if (editbox->textrender != NULL) { + SDL_DestroyTexture(editbox->textrender); + } + /* use our own font */ + editbox->textrender = KW_RenderTextLine(KW_GetEditboxFont(editbox->widget), + KW_GetWidgetRenderer(editbox->widget), + editbox->text, editbox->color, + TTF_STYLE_NORMAL); + + if (editbox->textrender != NULL) + SDL_QueryTexture(editbox->textrender, NULL, NULL, &(editbox->textwidth), + &(editbox->textheight)); + else + TTF_SizeUTF8(KW_GetEditboxFont(editbox->widget), "", &(editbox->textwidth), &(editbox->textheight)); +} + +KW_Editbox * AllocEditbox() { + KW_Editbox * editbox = calloc(sizeof(*editbox), 1); + return editbox; +} + +void DestroyEditbox(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + free(editbox); +} +void AdjustCursor(KW_Editbox * editbox, int cursormove) { + char save; + int len = SDL_strlen(editbox->text); + + /* adjust cursormove, don't let it over/underflow. */ + if (cursormove > 0) { + if (editbox->cursor + cursormove > len) { + cursormove = len - editbox->cursor; + } + } else if (cursormove < 0) { + if (-cursormove > editbox->cursor) { + cursormove = -editbox->cursor; + } + } + + /* now account for UTF-8 */ + if (cursormove > 0) { + /* its a UTF-8 sequence */ + while (cursormove-- > 0) { + (void)( + isutf(editbox->text[++(editbox->cursor)]) + || isutf(editbox->text[++(editbox->cursor)]) + || isutf(editbox->text[++(editbox->cursor)]) + || ++(editbox->cursor) + ); + } + } else if (cursormove < 0) { + while (cursormove++ < 0) { + (void)( + isutf(editbox->text[--(editbox->cursor)]) + || isutf(editbox->text[--(editbox->cursor)]) + || isutf(editbox->text[--(editbox->cursor)]) + || --(editbox->cursor) + ); + } + } + + /* recalculate cursor position */ + save = editbox->text[editbox->cursor]; + editbox->text[editbox->cursor] = '\0'; + TTF_SizeUTF8(KW_GetEditboxFont(editbox->widget), editbox->text, &editbox->cursorx, NULL); + editbox->text[editbox->cursor] = save; +} + +void TextBackspace(KW_Editbox * editbox) { + AdjustCursor(editbox, -1); + TextDelete(editbox); +} + +void TextDelete(KW_Editbox * editbox) { + int i = 0; + int len = SDL_strlen(editbox->text); + int seq = u8_seqlen(editbox->text[editbox->cursor]); + printf("seqlen is %d\n", seq); + for (i = editbox->cursor; i < len; i++) { + editbox->text[i] = editbox->text[i + seq]; + } + RenderEditboxText(editbox); +} + +/* KiWi callbacks */ +void EditboxKeyDown(KW_Widget * widget, SDL_Keycode key, SDL_Scancode scan) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + switch (scan) { + /* set up cursor states */ + case SDL_SCANCODE_LEFT: + AdjustCursor(editbox, -1); + break; + case SDL_SCANCODE_RIGHT: + AdjustCursor(editbox, 1); + break; + + case SDL_SCANCODE_BACKSPACE: + TextBackspace(editbox); + break; + + case SDL_SCANCODE_DELETE: + TextDelete(editbox); + break; + + case SDL_SCANCODE_HOME: + AdjustCursor(editbox, -u8_strlen(editbox->text)); + break; + + case SDL_SCANCODE_END: + AdjustCursor(editbox, u8_strlen(editbox->text)); + break; + + default: + break; + } +} + +void EditboxTextInput(KW_Widget * widget, const char * text) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + int i = 0, insertlen, textlen, cursoradjust; + + /* make room in the middle */ + i = editbox->cursor; + insertlen = SDL_strlen(text); + cursoradjust = insertlen; + textlen = SDL_strlen(editbox->text); + + for (i = textlen; i >= editbox->cursor && i > 0; i--) { + editbox->text[textlen + insertlen - (textlen - i)] = editbox->text[i]; + } + + for (i = 0; i < insertlen; i++) { + editbox->text[editbox->cursor + i] = text[i]; + } + + /* correct insertlen if its utf8 because AdjustCursor is in terms + * of perceived chars */ + cursoradjust = u8_strlen(text); + AdjustCursor(editbox, cursoradjust); + RenderEditboxText(editbox); +} + +void EditboxMouseOver(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->mouseover = SDL_TRUE; +} + +void EditboxMouseLeave(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->mouseover = SDL_FALSE; +} + +void EditboxMousePress(KW_Widget * widget, int b) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->clicked = SDL_TRUE; +} + +void EditboxMouseRelease(KW_Widget * widget, int b) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->clicked = SDL_FALSE; +} + +void EditboxFocusGain(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->active = SDL_TRUE; + SDL_StartTextInput(); +} + +void EditboxFocusLose(KW_Widget * widget) { + KW_Editbox * editbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_EDITBOX); + editbox->active = SDL_FALSE; + SDL_StopTextInput(); +} + +void EditboxFontChanged(KW_GUI * gui, void * priv, TTF_Font * font) { + KW_Editbox * editbox = KW_GetWidgetData((KW_Widget*)priv, KW_WIDGETTYPE_EDITBOX); + RenderEditboxText(editbox); +} diff --git a/src/KW_editbox_internal.h b/src/KW_editbox_internal.h index 9b796c7..b85e459 100644 --- a/src/KW_editbox_internal.h +++ b/src/KW_editbox_internal.h @@ -1,51 +1,52 @@ -#ifndef KW_EDITBOX_INTERNAL_H -#define KW_EDITBOX_INTERNAL_H - -#include "SDL.h" -#include "KW_widget.h" - -typedef struct KW_Edtibox { - KW_Widget * widget; /* the widget we pertain to */ - - char text[1024]; /* the actual text */ - KW_Texture * textrender; /* the rendered text */ - KW_Font * font; /* font used to render text */ - unsigned int cursor; /* in which char index is the cursor */ - KW_bool mouseover; /* is mouse over the editbox */ - KW_bool clicked; /* was the editbox clicked */ - KW_bool active; /* is the editbox active */ - - int textwidth; /* total width of the rendered text */ - int textheight; /* total height of the rendered text */ - int cursorx; /* cursor x position inside text texture */ - int cursoradjustx; /* ajudstment in src.x text texture */ - KW_Color color; /* color used to render the text */ - -} KW_Editbox; - - -/* util functions */ -void RenderEditboxText(KW_Editbox * editbox); -void PaintEditboxText(KW_Editbox * editbox, KW_Rect * geom); -void AdjustCursor(KW_Editbox * editbox, int cursormove); -KW_Editbox * AllocEditbox(); -void TextBackspace(KW_Editbox * editbox); -void TextDelete(KW_Editbox * editbox); - -/* main callbacks */ -void DestroyEditbox(KW_Widget * widget); -void PaintEditbox(KW_Widget * widget); - -/* event callbacks */ -void EditboxMouseOver(KW_Widget * widget); -void EditboxMouseLeave(KW_Widget * widget); -void EditboxMousePress(KW_Widget * widget, int b); -void EditboxMouseRelease(KW_Widget * widget, int b); -void EditboxFocusGain(KW_Widget * widget); -void EditboxFocusLose(KW_Widget * widget); -void EditboxTextInput(KW_Widget * widget, const char * text); -void EditboxKeyDown(KW_Widget * widget, SDL_Keycode key, SDL_Scancode sym); -void EditboxFontChanged(KW_GUI * gui, void * priv, KW_Font * font); - - -#endif +#ifndef KW_EDITBOX_INTERNAL_H +#define KW_EDITBOX_INTERNAL_H + +#include "SDL.h" +#include "SDL_ttf.h" +#include "KW_widget.h" + +typedef struct KW_Edtibox { + KW_Widget * widget; /* the widget we pertain to */ + + char text[1024]; /* the actual text */ + SDL_Texture * textrender; /* the rendered text */ + TTF_Font * font; /* font used to render text */ + unsigned int cursor; /* in which char index is the cursor */ + SDL_bool mouseover; /* is mouse over the editbox */ + SDL_bool clicked; /* was the editbox clicked */ + SDL_bool active; /* is the editbox active */ + + int textwidth; /* total width of the rendered text */ + int textheight; /* total height of the rendered text */ + int cursorx; /* cursor x position inside text texture */ + int cursoradjustx; /* ajudstment in src.x text texture */ + SDL_Color color; /* color used to render the text */ + +} KW_Editbox; + + +/* util functions */ +void RenderEditboxText(KW_Editbox * editbox); +void PaintEditboxText(KW_Editbox * editbox, SDL_Rect * geom); +void AdjustCursor(KW_Editbox * editbox, int cursormove); +KW_Editbox * AllocEditbox(); +void TextBackspace(KW_Editbox * editbox); +void TextDelete(KW_Editbox * editbox); + +/* main callbacks */ +void DestroyEditbox(KW_Widget * widget); +void PaintEditbox(KW_Widget * widget); + +/* event callbacks */ +void EditboxMouseOver(KW_Widget * widget); +void EditboxMouseLeave(KW_Widget * widget); +void EditboxMousePress(KW_Widget * widget, int b); +void EditboxMouseRelease(KW_Widget * widget, int b); +void EditboxFocusGain(KW_Widget * widget); +void EditboxFocusLose(KW_Widget * widget); +void EditboxTextInput(KW_Widget * widget, const char * text); +void EditboxKeyDown(KW_Widget * widget, SDL_Keycode key, SDL_Scancode sym); +void EditboxFontChanged(KW_GUI * gui, void * priv, TTF_Font * font); + + +#endif diff --git a/src/KW_eventwatcher.c b/src/KW_eventwatcher.c index 8eb0a4a..38f4814 100644 --- a/src/KW_eventwatcher.c +++ b/src/KW_eventwatcher.c @@ -1,226 +1,232 @@ -#include "KW_eventwatcher.h" -#include "KW_gui_internal.h" -#include "KW_widget_internal.h" - -KW_Widget * CalculateMouseOver(KW_Widget * widget, int x, int y) { - int i; - KW_Widget * found = NULL; - KW_Rect g = widget->composed; - if (widget->parent) { - g.x += widget->parent->absolute.x; - g.y += widget->parent->absolute.y; - } - /* mouseover is a input event, avoid calculating it */ - if (KW_IsWidgetInputEventsBlocked(widget)) { - return NULL; - } - - /* if not in composed geometry, nothing to see here then. rootwidget always borked. */ - if (!(x > g.x && x < g.x + g.w && y > g.y && y < g.y + g.h) && widget != widget->gui->rootwidget) { - return NULL; - } - - for (i = widget->childrencount-1; i >= 0 && found == NULL; i--) - found = CalculateMouseOver(widget->children[i], x, y); - - /* children don't have it. Maybe its this widget then? */ - if (found == NULL) { - g = widget->absolute; - /* use our own absolute to test, then */ - if (x > g.x && x < g.x + g.w && y > g.y && y < g.y + g.h) - found = widget; - } - return found; -} - -void MouseMoved(KW_GUI * gui, int mousex, int mousey, int xrel, int yrel) { - int i, count; - KW_OnMouseOver * overhandlers; - KW_OnMouseLeave * leavehandlers; - KW_OnDragStart * dragstarthandlers; - KW_OnDrag * draghandlers; - KW_Widget * current = gui->currentmouseover; - KW_Widget * widget = NULL; - - /* first check if we are in drag mode */ - if (gui->cursordown == SDL_TRUE) { - /* check if drag is starting */ - if (gui->currentdrag == NULL) { - /* drag is starting on the current mouse over */ - if (current != NULL) { - /* report dragstart */ - count = current->eventhandlers[KW_ON_DRAGSTART].count; - dragstarthandlers = (KW_OnDragStart *) current->eventhandlers[KW_ON_DRAGSTART].handlers; - for (i = 0; i < count; i++) { - dragstarthandlers[i](current, mousex, mousey); - } - /* sets the currend drag widget */ - gui->currentdrag = current; - } - } else { - /* drag HAS started already. Update widh drag positions */ - count = current->eventhandlers[KW_ON_DRAG].count; - draghandlers = (KW_OnDrag *) current->eventhandlers[KW_ON_DRAG].handlers; - for (i = 0; i < count; i++) { - draghandlers[i](current, mousex, mousey, xrel, yrel); - } - } - - /* no mouse movement events are calculated while dragging */ - return; - } - - widget = CalculateMouseOver(gui->rootwidget, mousex, mousey); - if (widget == current) return; - - /* gotta notify the previous mouseover */ - if (current != NULL) { - count = current->eventhandlers[KW_ON_MOUSELEAVE].count; - leavehandlers = (KW_OnMouseLeave *) current->eventhandlers[KW_ON_MOUSELEAVE].handlers; - for (i = 0; i < count; i++) { - leavehandlers[i](current); - } - } - - /* warn the current mouseover */ - gui->currentmouseover = widget; - if (widget != NULL) { - count = widget->eventhandlers[KW_ON_MOUSEOVER].count; - overhandlers = (KW_OnMouseOver *) widget->eventhandlers[KW_ON_MOUSEOVER].handlers; - for (i = 0; i < count; i++) { - overhandlers[i](widget); - } - } -} - - -void MousePressed(KW_GUI * gui, int mousex, int mousey, int button) { - int i, count; - KW_OnMouseDown * handlers; - KW_Widget * widget = gui->currentmouseover; - if (widget != NULL) { - count = widget->eventhandlers[KW_ON_MOUSEDOWN].count; - handlers = (KW_OnMouseDown *) widget->eventhandlers[KW_ON_MOUSEDOWN].handlers; - for (i = 0; i < count; i++) { - handlers[i](widget, button); - } - } - gui->cursordown = SDL_TRUE; -} - -void MouseReleased(KW_GUI * gui, int mousex, int mousey, int button) { - int i, count; - KW_OnMouseUp * upandlers; - KW_OnDragStop * dragstophandlers; - KW_Widget * widget = gui->currentmouseover; - - gui->cursordown = SDL_FALSE; - - /* check if was under drag */ - if (gui->currentdrag != NULL) { - count = widget->eventhandlers[KW_ON_DRAGSTOP].count; - dragstophandlers = (KW_OnDragStop *) widget->eventhandlers[KW_ON_DRAGSTOP].handlers; - for (i = 0; i < count; i++) { - dragstophandlers[i](widget, mousex, mousey); - } - gui->currentdrag = NULL; - - /* force a mouse move to calculate mouseover again. */ - MouseMoved(gui, mousex, mousey, 0, 0); - } - - if (widget != NULL) { - count = widget->eventhandlers[KW_ON_MOUSEUP].count; - upandlers = (KW_OnMouseUp *) widget->eventhandlers[KW_ON_MOUSEUP].handlers; - for (i = 0; i < count; i++) { - upandlers[i](widget, button); - } - } - - KW_SetFocusedWidget(widget); -} - -void TextInputReady(KW_GUI * gui, const char * text) { - int count, i; - KW_OnTextInput * handlers; - if (gui->currentfocus == NULL) return; - count = gui->currentfocus->eventhandlers[KW_ON_TEXTINPUT].count; - handlers = (KW_OnTextInput*) gui->currentfocus->eventhandlers[KW_ON_TEXTINPUT].handlers; - for (i = 0; i < count; i++) { - handlers[i](gui->currentfocus, text); - } -} - -void KeyUp(KW_GUI * gui, SDL_Keycode key, SDL_Scancode scan) { - int count, i; - KW_OnKeyUp * handlers; - if (gui->currentfocus == NULL) return; - count = gui->currentfocus->eventhandlers[KW_ON_KEYUP].count; - handlers = (KW_OnKeyUp*) gui->currentfocus->eventhandlers[KW_ON_KEYUP].handlers; - for (i = 0; i < count; i++) { - handlers[i](gui->currentfocus, key, scan); - } -} - -void KeyDown(KW_GUI * gui, SDL_Keycode key, SDL_Scancode scan) { - int count, i; - KW_OnKeyDown * handlers; - if (gui->currentfocus == NULL) return; - count = gui->currentfocus->eventhandlers[KW_ON_KEYDOWN].count; - handlers = (KW_OnKeyDown*) gui->currentfocus->eventhandlers[KW_ON_KEYDOWN].handlers; - for (i = 0; i < count; i++) { - handlers[i](gui->currentfocus, key, scan); - } -} - -/* to capture mouse movements, clicks, types, etc */ -int KW_EventWatcher(void * data, SDL_Event * event) { - KW_GUI * gui = (KW_GUI *) data; - SDL_LockMutex(gui->evqueuelock); - gui->evqueue[(gui->evqueuesize)++] = *event; - SDL_UnlockMutex(gui->evqueuelock); - return 0; -} - -int KW_ProcessEvents(KW_GUI * gui) { - int i = 0; - SDL_LockMutex(gui->evqueuelock); - for (i = 0; i < gui->evqueuesize; i++) { - SDL_Event * event = gui->evqueue + i; - switch (event->type) { - case SDL_MOUSEMOTION: - MouseMoved(gui, event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel); - break; - case SDL_MOUSEBUTTONDOWN: - MousePressed(gui, event->button.x, event->button.y, event->button.button); - break; - - case SDL_MOUSEBUTTONUP: - MouseReleased(gui, event->button.x, event->button.y, event->button.button); - break; - - case SDL_TEXTINPUT: - SDL_Log("Got a textready: %s\n", event->text.text); - TextInputReady(gui, event->text.text); - break; - - case SDL_TEXTEDITING: - SDL_Log("Got a textediting: %d %d %d %s\n", event->edit.start, event->edit.length, event->edit.type, event->edit.text); - break; - - case SDL_KEYDOWN: - KeyDown(gui, event->key.keysym.sym, event->key.keysym.scancode); - break; - case SDL_KEYUP: - KeyUp(gui, event->key.keysym.sym, event->key.keysym.scancode); - break; - default: - break; - } - } - gui->evqueuesize = 0; - SDL_UnlockMutex(gui->evqueuelock); - - return 0; -} -#undef NDEBUG +#include "KW_eventwatcher.h" +#include "KW_gui_internal.h" +#include "KW_widget_internal.h" + +KW_Widget * CalculateMouseOver(KW_Widget * widget, int x, int y) { + int i; + KW_Widget * found = NULL; + SDL_Rect g = widget->composed; + if (widget->parent) { + g.x += widget->parent->absolute.x; + g.y += widget->parent->absolute.y; + } + /* mouseover is a input event, avoid calculating it */ + if (KW_IsWidgetInputEventsBlocked(widget)) { + return NULL; + } + + /* if not in composed geometry, nothing to see here then. rootwidget always borked. */ + if (!(x > g.x && x < g.x + g.w && y > g.y && y < g.y + g.h) && widget != widget->gui->rootwidget) { + return NULL; + } + + for (i = widget->childrencount-1; i >= 0 && found == NULL; i--) + found = CalculateMouseOver(widget->children[i], x, y); + + /* children don't have it. Maybe its this widget then? */ + if (found == NULL) { + g = widget->absolute; + /* use our own absolute to test, then */ + if (x > g.x && x < g.x + g.w && y > g.y && y < g.y + g.h) + found = widget; + } + return found; +} + +void KW_SetMouseOverWidget(KW_GUI * gui, KW_Widget * widget) { + int count, i; + KW_OnMouseOver * overhandlers; + KW_OnMouseLeave * leavehandlers; + KW_Widget * current = gui->currentmouseover; + if (widget == current) return; + + /* gotta notify the previous mouseover */ + if (current != NULL) { + count = current->eventhandlers[KW_ON_MOUSELEAVE].count; + leavehandlers = (KW_OnMouseLeave *) current->eventhandlers[KW_ON_MOUSELEAVE].handlers; + for (i = 0; i < count; i++) { + leavehandlers[i](current); + } + } + + /* warn the current mouseover */ + gui->currentmouseover = widget; + if (widget != NULL) { + count = widget->eventhandlers[KW_ON_MOUSEOVER].count; + overhandlers = (KW_OnMouseOver *) widget->eventhandlers[KW_ON_MOUSEOVER].handlers; + for (i = 0; i < count; i++) { + overhandlers[i](widget); + } + } +} + +void MouseMoved(KW_GUI * gui, int mousex, int mousey, int xrel, int yrel) { + int i, count; + KW_OnDragStart * dragstarthandlers; + KW_OnDrag * draghandlers; + KW_Widget * current = gui->currentmouseover; + KW_Widget * widget = NULL; + + /* first check if we are in drag mode */ + if (gui->cursordown == SDL_TRUE) { + /* check if drag is starting */ + if (gui->currentdrag == NULL) { + /* drag is starting on the current mouse over */ + if (current != NULL) { + /* report dragstart */ + count = current->eventhandlers[KW_ON_DRAGSTART].count; + dragstarthandlers = (KW_OnDragStart *) current->eventhandlers[KW_ON_DRAGSTART].handlers; + for (i = 0; i < count; i++) { + dragstarthandlers[i](current, mousex, mousey); + } + /* sets the currend drag widget */ + gui->currentdrag = current; + } + } else { + /* drag HAS started already. Update widh drag positions */ + count = current->eventhandlers[KW_ON_DRAG].count; + draghandlers = (KW_OnDrag *) current->eventhandlers[KW_ON_DRAG].handlers; + for (i = 0; i < count; i++) { + draghandlers[i](current, mousex, mousey, xrel, yrel); + } + } + + /* no mouse movement events are calculated while dragging */ + return; + } + + widget = CalculateMouseOver(gui->rootwidget, mousex, mousey); + KW_SetMouseOverWidget(gui, widget); +} + +void MousePressed(KW_GUI * gui, int mousex, int mousey, int button) { + int i, count; + KW_OnMouseDown * handlers; + KW_Widget * widget = gui->currentmouseover; + if (widget != NULL) { + count = widget->eventhandlers[KW_ON_MOUSEDOWN].count; + handlers = (KW_OnMouseDown *) widget->eventhandlers[KW_ON_MOUSEDOWN].handlers; + for (i = 0; i < count; i++) { + handlers[i](widget, button); + } + } + gui->cursordown = SDL_TRUE; +} + +void MouseReleased(KW_GUI * gui, int mousex, int mousey, int button) { + int i, count; + KW_OnMouseUp * upandlers; + KW_OnDragStop * dragstophandlers; + KW_Widget* widget = gui->currentmouseover; + + gui->cursordown = SDL_FALSE; + + /* check if was under drag */ + if (gui->currentdrag != NULL) { + count = widget->eventhandlers[KW_ON_DRAGSTOP].count; + dragstophandlers = (KW_OnDragStop *) widget->eventhandlers[KW_ON_DRAGSTOP].handlers; + for (i = 0; i < count; i++) { + dragstophandlers[i](widget, mousex, mousey); + } + gui->currentdrag = NULL; + + /* force a mouse move to calculate mouseover again. */ + MouseMoved(gui, mousex, mousey, 0, 0); + } + + if (widget != NULL) { + count = widget->eventhandlers[KW_ON_MOUSEUP].count; + upandlers = (KW_OnMouseUp *) widget->eventhandlers[KW_ON_MOUSEUP].handlers; + for (i = 0; i < count; i++) { + upandlers[i](widget, button); + } + } + + /* gui->currentmouseover might have changed in one of the handlers */ + KW_SetFocusedWidget(gui->currentmouseover); +} + +void TextInputReady(KW_GUI * gui, const char * text) { + int count, i; + KW_OnTextInput * handlers; + if (gui->currentfocus == NULL) return; + count = gui->currentfocus->eventhandlers[KW_ON_TEXTINPUT].count; + handlers = (KW_OnTextInput*) gui->currentfocus->eventhandlers[KW_ON_TEXTINPUT].handlers; + for (i = 0; i < count; i++) { + handlers[i](gui->currentfocus, text); + } +} + +void KeyUp(KW_GUI * gui, SDL_Keycode key, SDL_Scancode scan) { + int count, i; + KW_OnKeyUp * handlers; + if (gui->currentfocus == NULL) return; + count = gui->currentfocus->eventhandlers[KW_ON_KEYUP].count; + handlers = (KW_OnKeyUp*) gui->currentfocus->eventhandlers[KW_ON_KEYUP].handlers; + for (i = 0; i < count; i++) { + handlers[i](gui->currentfocus, key, scan); + } +} + +void KeyDown(KW_GUI * gui, SDL_Keycode key, SDL_Scancode scan) { + int count, i; + KW_OnKeyDown * handlers; + if (gui->currentfocus == NULL) return; + count = gui->currentfocus->eventhandlers[KW_ON_KEYDOWN].count; + handlers = (KW_OnKeyDown*) gui->currentfocus->eventhandlers[KW_ON_KEYDOWN].handlers; + for (i = 0; i < count; i++) { + handlers[i](gui->currentfocus, key, scan); + } +} + +/* to capture mouse movements, clicks, types, etc */ +int KW_EventWatcher(void * data, SDL_Event * event) { + KW_GUI * gui = (KW_GUI *) data; + SDL_LockMutex(gui->evqueuelock); + gui->evqueue[(gui->evqueuesize)++] = *event; + SDL_UnlockMutex(gui->evqueuelock); + return 0; +} + +int KW_ProcessEvents(KW_GUI * gui) { + int i = 0; + SDL_LockMutex(gui->evqueuelock); + for (i = 0; i < gui->evqueuesize; i++) { + SDL_Event * event = gui->evqueue + i; + switch (event->type) { + case SDL_MOUSEMOTION: + MouseMoved(gui, event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel); + break; + case SDL_MOUSEBUTTONDOWN: + MousePressed(gui, event->button.x, event->button.y, event->button.button); + break; + + case SDL_MOUSEBUTTONUP: + MouseReleased(gui, event->button.x, event->button.y, event->button.button); + break; + + case SDL_TEXTINPUT: + SDL_Log("Got a textready: %s\n", event->text.text); + TextInputReady(gui, event->text.text); + break; + + case SDL_TEXTEDITING: + SDL_Log("Got a textediting: %d %d %d %s\n", event->edit.start, event->edit.length, event->edit.type, event->edit.text); + break; + + case SDL_KEYDOWN: + KeyDown(gui, event->key.keysym.sym, event->key.keysym.scancode); + break; + case SDL_KEYUP: + KeyUp(gui, event->key.keysym.sym, event->key.keysym.scancode); + break; + default: + break; + } + } + gui->evqueuesize = 0; + SDL_UnlockMutex(gui->evqueuelock); + + return 0; +} +#undef NDEBUG diff --git a/src/KW_eventwatcher.h b/src/KW_eventwatcher.h index 6855870..647037e 100644 --- a/src/KW_eventwatcher.h +++ b/src/KW_eventwatcher.h @@ -1,44 +1,44 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_EVENTWATCHER_H -#define KW_EVENTWATCHER_H - -#include "KW_gui.h" -#include "SDL.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -int KW_EventWatcher(void * gui, SDL_Event * event); -int KW_ProcessEvents(KW_GUI * gui); - -#ifdef __cplusplus -} -#endif - - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_EVENTWATCHER_H +#define KW_EVENTWATCHER_H + +#include "KW_gui.h" +#include "SDL.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int KW_EventWatcher(void * gui, SDL_Event * event); +int KW_ProcessEvents(KW_GUI * gui); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/KW_frame.c b/src/KW_frame.c index 06ade6e..75d1c21 100644 --- a/src/KW_frame.c +++ b/src/KW_frame.c @@ -1,16 +1,16 @@ -#include "KW_gui.h" -#include "KW_frame.h" -#include "SDL.h" -#include "KW_tilerenderer.h" -#include "KW_frame_internal.h" - -void PaintFrame(KW_Widget * frame); - -KW_Widget * KW_CreateFrame(KW_GUI * gui, KW_Widget * parent, const KW_Rect * geometry) { - KW_Frame * frame = AllocFrame(); - KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_FRAME, geometry, PaintFrame, DestroyFrame, frame); - KW_AddWidgetGeometryChangeHandler(widget, FrameGeometryChanged); - RenderFrame(widget); - return widget; -} - +#include "KW_gui.h" +#include "KW_frame.h" +#include "SDL.h" +#include "KW_tilerenderer.h" +#include "KW_frame_internal.h" + +void PaintFrame(KW_Widget * frame); + +KW_Widget * KW_CreateFrame(KW_GUI * gui, KW_Widget * parent, const SDL_Rect * geometry) { + KW_Frame * frame = AllocFrame(); + KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_FRAME, geometry, PaintFrame, DestroyFrame, frame); + KW_AddWidgetGeometryChangeHandler(widget, FrameGeometryChanged); + RenderFrame(widget); + return widget; +} + diff --git a/src/KW_frame.h b/src/KW_frame.h index 03e5d0b..7c0c2a7 100644 --- a/src/KW_frame.h +++ b/src/KW_frame.h @@ -1,55 +1,55 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_FRAME_H -#define KW_FRAME_H - -/** - * \file KW_frame.h - * - * Defines functions related to the frame KW_Widget - */ - -#include "KW_widget.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Creates a frame widget. - * \details The frame is constructed by arranging the the first 3x3 tiles in the tileset. - * \param gui The KW_GUI instance that will hold this widget. - * \param parent The parent widget of this widget. - * \param geometry The relative geometry of this frame. - * \return The frame instance. - */ -extern DECLSPEC KW_Widget * KW_CreateFrame(KW_GUI * gui, KW_Widget * parent, const KW_Rect * geometry); - -#ifdef __cplusplus -} -#endif - - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_FRAME_H +#define KW_FRAME_H + +/** + * \file KW_frame.h + * + * Defines functions related to the frame KW_Widget + */ + +#include "KW_widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Creates a frame widget. + * \details The frame is constructed by arranging the the first 3x3 tiles in the tileset. + * \param gui The KW_GUI instance that will hold this widget. + * \param parent The parent widget of this widget. + * \param geometry The relative geometry of this frame. + * \return The frame instance. + */ +extern DECLSPEC KW_Widget * KW_CreateFrame(KW_GUI * gui, KW_Widget * parent, const SDL_Rect * geometry); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/KW_frame_internal.c b/src/KW_frame_internal.c index 7967928..2a1515f 100644 --- a/src/KW_frame_internal.c +++ b/src/KW_frame_internal.c @@ -1,44 +1,44 @@ -#include "KW_widget.h" -#include "KW_tilerenderer.h" -#include "KW_frame_internal.h" -#include "KW_gui.h" -#include "SDL.h" - -KW_Frame * AllocFrame() { - KW_Frame * frame = calloc(sizeof(*frame), 1); - return frame; -} - -void DestroyFrame(KW_Widget * widget) { - KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); - SDL_DestroyTexture(frame->framerender); - free(frame); -} - - -void RenderFrame(KW_Widget * widget) { - KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); - KW_Rect targetgeom; - KW_Surface * tileset = KW_GetWidgetTilesetSurface(widget); - KW_GetWidgetGeometry(widget, &targetgeom); - if (frame->framerender != NULL) SDL_DestroyTexture(frame->framerender); - frame->framerender = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 0, 0, targetgeom.w, targetgeom.h); -} - -void PaintFrame(KW_Widget * widget) { - KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); - KW_Rect targetgeom; - KW_RenderDriver * renderer; - - KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); - renderer = KW_GetWidgetRenderer(widget); - - KW_RenderCopy(renderer, frame->framerender, NULL, &targetgeom); -} - - -void FrameGeometryChanged(KW_Widget * widget, const KW_Rect * newgeom, const KW_Rect * oldgeom) { - if (newgeom->w != oldgeom->w || newgeom->h != newgeom->h) { - RenderFrame(widget); - } -} +#include "KW_widget.h" +#include "KW_tilerenderer.h" +#include "KW_frame_internal.h" +#include "KW_gui.h" +#include "SDL.h" + +KW_Frame * AllocFrame() { + KW_Frame * frame = calloc(sizeof(*frame), 1); + return frame; +} + +void DestroyFrame(KW_Widget * widget) { + KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); + SDL_DestroyTexture(frame->framerender); + free(frame); +} + + +void RenderFrame(KW_Widget * widget) { + KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); + SDL_Rect targetgeom; + SDL_Surface * tileset = KW_GetWidgetTilesetSurface(widget); + KW_GetWidgetGeometry(widget, &targetgeom); + if (frame->framerender != NULL) SDL_DestroyTexture(frame->framerender); + frame->framerender = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 0, 0, targetgeom.w, targetgeom.h); +} + +void PaintFrame(KW_Widget * widget) { + KW_Frame * frame = KW_GetWidgetData(widget, KW_WIDGETTYPE_FRAME); + SDL_Rect targetgeom; + SDL_Renderer * renderer; + + KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); + renderer = KW_GetWidgetRenderer(widget); + + SDL_RenderCopy(renderer, frame->framerender, NULL, &targetgeom); +} + + +void FrameGeometryChanged(KW_Widget * widget, const SDL_Rect * newgeom, const SDL_Rect * oldgeom) { + if (newgeom->w != oldgeom->w || newgeom->h != newgeom->h) { + RenderFrame(widget); + } +} diff --git a/src/KW_frame_internal.h b/src/KW_frame_internal.h index 0afe18c..bb0de4c 100644 --- a/src/KW_frame_internal.h +++ b/src/KW_frame_internal.h @@ -1,16 +1,16 @@ -#ifndef KW_FRAME_INTERNAL_H -#define KW_FRAME_INTERNAL_H - -#include "SDL.h" - -typedef struct KW_Frame { - SDL_Texture * framerender; -} KW_Frame; - -KW_Frame * AllocFrame(); -void RenderFrame(KW_Widget * widget); -void PaintFrame(KW_Widget * widget); -void DestroyFrame(KW_Widget * widget); -void FrameGeometryChanged(KW_Widget * widget, const KW_Rect * newrect, const KW_Rect * old); - -#endif +#ifndef KW_FRAME_INTERNAL_H +#define KW_FRAME_INTERNAL_H + +#include "SDL.h" + +typedef struct KW_Frame { + SDL_Texture * framerender; +} KW_Frame; + +KW_Frame * AllocFrame(); +void RenderFrame(KW_Widget * widget); +void PaintFrame(KW_Widget * widget); +void DestroyFrame(KW_Widget * widget); +void FrameGeometryChanged(KW_Widget * widget, const SDL_Rect * newrect, const SDL_Rect * old); + +#endif diff --git a/src/KW_gui.c b/src/KW_gui.c index f88f8cd..acd19bd 100644 --- a/src/KW_gui.c +++ b/src/KW_gui.c @@ -1,137 +1,139 @@ -#include "KW_widget_internal.h" -#include "KW_widget.h" -#include "KW_gui.h" -#include "KW_gui_internal.h" -#include "KW_eventwatcher.h" -#include "KW_renderdriver.h" - -KW_GUI * KW_Init(KW_RenderDriver * renderer, KW_Surface * tileset) { - struct KW_GUI * gui = calloc(sizeof(*gui), 1); - gui->renderer = renderer; - KW_SetTilesetSurface(gui, tileset); - gui->rootwidget = AllocWidget(); - gui->rootwidget->gui = gui; - gui->evqueuelock = SDL_CreateMutex(); - - SDL_AddEventWatch(KW_EventWatcher, (void*)gui); - - return gui; -} - - - -void KW_SetRender(KW_GUI * gui, KW_RenderDriver * renderer) { - gui->renderer = renderer; -} - -void KW_SetTilesetSurface(KW_GUI * gui, KW_Surface * tileset) { - gui->tilesettexture = KW_CreateTexture(gui->renderer, tileset); - gui->tilesetsurface = tileset; -} - - -KW_RenderDriver * KW_GetRenderer(KW_GUI * gui) { - return gui->renderer; -} - - -void KW_SetRenderer(KW_GUI * gui, KW_RenderDriver * renderer) { - gui->renderer = renderer; -} - - -KW_Texture * KW_GetTilesetTexture(KW_GUI * gui) { - return gui->tilesettexture; -} - -KW_Texture * KW_GetTilesetSurface(KW_GUI * gui) { - return gui->tilesetsurface; -} - - -void KW_Quit(KW_GUI * gui) { - KW_DestroyWidget(gui->rootwidget, 1); - free(gui); -} - -void KW_SetFont(KW_GUI * gui, KW_Font * font) { - int i = 0; - KW_OnGUIFontChanged handler; - if (font == NULL) return; - gui->font = font; - - for (i = 0; i < gui->eventhandlers[KW_GUI_ONFONTCHANGED].count; i++) { - handler = (KW_OnGUIFontChanged) gui->eventhandlers[KW_GUI_ONFONTCHANGED].handlers[i].handler; - handler(gui, gui->eventhandlers[KW_GUI_ONFONTCHANGED].handlers[i].priv, font); - } - return; -} - -void KW_AddGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv) { - AddGUIHandler(gui, KW_GUI_ONFONTCHANGED, (GUIHandler) handler, priv); -} - -void KW_RemoveGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv) { - RemoveGUItHandler(gui, KW_GUI_ONFONTCHANGED, (GUIHandler) handler, priv); -} - -KW_Font * KW_GetFont(KW_GUI * gui) { - return gui->font; -} - - -KW_GUI * KW_GetGUI(const KW_Widget * widget) { - return KW_GetWidgetGUI(widget); -} - -void KW_Paint(KW_GUI * gui) { - KW_ProcessEvents(gui); - KW_PaintWidget(gui->rootwidget); -} - -/* generic handler list functions */ - -void AddGUIHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv) { - /* don't add multiple mouse over handlers */ - unsigned int * count = &(gui->eventhandlers[handlertype].count); - - /* check if handler is there */ - int i; - for (i = 0; i < *count; ++i) { - if (gui->eventhandlers[handlertype].handlers[i].handler == handler && gui->eventhandlers[handlertype].handlers[i].priv == priv) - return; - } - - /* add the handler then */ - (*count)++; - gui->eventhandlers[handlertype].handlers = realloc(gui->eventhandlers[handlertype].handlers, sizeof(struct KW_GUICallback) * (*count)); - gui->eventhandlers[handlertype].handlers[(*count) - 1].handler = handler; - gui->eventhandlers[handlertype].handlers[(*count) - 1].priv = priv; -} - -void RemoveGUItHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv) { - int i, j; - unsigned int * count = &(gui->eventhandlers[handlertype].count); - - /* iterate to find the position of gui */ - for (i = 0; i < *count; i++) { - if (gui->eventhandlers[handlertype].handlers[i].handler == handler) { - if (gui->eventhandlers[handlertype].handlers[i].priv == priv) - j = i; - } - - /* move everything in front of it */ - if (j >= 0 && i + 1 < *count) { - gui->eventhandlers[handlertype].handlers[i] = gui->eventhandlers[handlertype].handlers[i+1]; - } - } - - /* realloc children array */ - (*count)--; - if (*count <= 0) { - free(gui->eventhandlers[handlertype].handlers); - gui->eventhandlers[handlertype].handlers = NULL; - } - else - gui->eventhandlers[handlertype].handlers = realloc(gui->eventhandlers[handlertype].handlers, *count * sizeof(struct KW_GUICallback)); -} +#include "KW_widget_internal.h" +#include "KW_widget.h" +#include "KW_gui.h" +#include "KW_gui_internal.h" +#include "KW_eventwatcher.h" + +#include "SDL_ttf.h" + +KW_GUI * KW_Init(SDL_Renderer * renderer, SDL_Surface * tileset) { + struct KW_GUI * gui = calloc(sizeof(*gui), 1); + gui->renderer = renderer; + KW_SetTilesetSurface(gui, tileset); + gui->rootwidget = AllocWidget(); + gui->rootwidget->gui = gui; + gui->evqueuelock = SDL_CreateMutex(); + + SDL_AddEventWatch(KW_EventWatcher, (void*)gui); + + return gui; +} + + + +void KW_SetRender(KW_GUI * gui, SDL_Renderer * renderer) { + gui->renderer = renderer; +} + +void KW_SetTilesetSurface(KW_GUI * gui, SDL_Surface * tileset) { + gui->tilesettexture = SDL_CreateTextureFromSurface(gui->renderer, tileset); + SDL_SetSurfaceBlendMode(tileset, SDL_BLENDMODE_NONE); + gui->tilesetsurface = tileset; +} + + +SDL_Renderer * KW_GetRenderer(KW_GUI * gui) { + return gui->renderer; +} + + +void KW_SetRenderer(KW_GUI * gui, SDL_Renderer * renderer) { + gui->renderer = renderer; +} + + +SDL_Texture * KW_GetTilesetTexture(KW_GUI * gui) { + return gui->tilesettexture; +} + +SDL_Surface * KW_GetTilesetSurface(KW_GUI * gui) { + return gui->tilesetsurface; +} + + +void KW_Quit(KW_GUI * gui) { + KW_DestroyWidget(gui->rootwidget, 1); + free(gui); +} + +void KW_SetFont(KW_GUI * gui, TTF_Font * font) { + int i = 0; + KW_OnGUIFontChanged handler; + if (font == NULL) return; + gui->font = font; + + for (i = 0; i < gui->eventhandlers[KW_GUI_ONFONTCHANGED].count; i++) { + handler = (KW_OnGUIFontChanged) gui->eventhandlers[KW_GUI_ONFONTCHANGED].handlers[i].handler; + handler(gui, gui->eventhandlers[KW_GUI_ONFONTCHANGED].handlers[i].priv, font); + } + return; +} + +void KW_AddGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv) { + AddGUIHandler(gui, KW_GUI_ONFONTCHANGED, (GUIHandler) handler, priv); +} + +void KW_RemoveGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv) { + RemoveGUItHandler(gui, KW_GUI_ONFONTCHANGED, (GUIHandler) handler, priv); +} + +TTF_Font * KW_GetFont(KW_GUI * gui) { + return gui->font; +} + + +KW_GUI * KW_GetGUI(const KW_Widget * widget) { + return KW_GetWidgetGUI(widget); +} + +void KW_Paint(KW_GUI * gui) { + KW_ProcessEvents(gui); + KW_PaintWidget(gui->rootwidget); +} + +/* generic handler list functions */ + +void AddGUIHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv) { + /* don't add multiple mouse over handlers */ + unsigned int * count = &(gui->eventhandlers[handlertype].count); + + /* check if handler is there */ + int i; + for (i = 0; i < *count; ++i) { + if (gui->eventhandlers[handlertype].handlers[i].handler == handler && gui->eventhandlers[handlertype].handlers[i].priv == priv) + return; + } + + /* add the handler then */ + (*count)++; + gui->eventhandlers[handlertype].handlers = realloc(gui->eventhandlers[handlertype].handlers, sizeof(struct KW_GUICallback) * (*count)); + gui->eventhandlers[handlertype].handlers[(*count) - 1].handler = handler; + gui->eventhandlers[handlertype].handlers[(*count) - 1].priv = priv; +} + +void RemoveGUItHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv) { + int i, j; + unsigned int * count = &(gui->eventhandlers[handlertype].count); + + /* iterate to find the position of gui */ + for (i = 0; i < *count; i++) { + if (gui->eventhandlers[handlertype].handlers[i].handler == handler) { + if (gui->eventhandlers[handlertype].handlers[i].priv == priv) + j = i; + } + + /* move everything in front of it */ + if (j >= 0 && i + 1 < *count) { + gui->eventhandlers[handlertype].handlers[i] = gui->eventhandlers[handlertype].handlers[i+1]; + } + } + + /* realloc children array */ + (*count)--; + if (*count <= 0) { + free(gui->eventhandlers[handlertype].handlers); + gui->eventhandlers[handlertype].handlers = NULL; + } + else + gui->eventhandlers[handlertype].handlers = realloc(gui->eventhandlers[handlertype].handlers, *count * sizeof(struct KW_GUICallback)); +} diff --git a/src/KW_gui.h b/src/KW_gui.h index e201bd2..207dd88 100644 --- a/src/KW_gui.h +++ b/src/KW_gui.h @@ -1,180 +1,191 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_GUI_H -#define KW_GUI_H - -#include "KW_macros.h" -#include "KW_widget.h" -#include "KW_renderdriver.h" - -/** - * \file KW_gui.h - * - * Main include for the KiWi library. - */ - - -/** - * \mainpage KiWi - * - * http://www.libsdl.org/ - * - * \section intro_sec Introduction - * - * KiWi is a widget-based GUI library for 2D games using SDL2. Its widgets - * are built from a tileset allowing you to customize the looks of your GUI - * by simply changing the source tile set. - * - * You can also create custom widgets. - * - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief The KW_GUI type holds information shared by all widgets. - * \details You need a KW_GUI instance to create widgets. - */ - -typedef void (*KW_OnGUIFontChanged)(KW_GUI * gui, void * data, KW_Font * font); - -/** - * \brief Initializes a new KW_GUI instance. - * \details Each KW_Widget should be associated with a KW_GUI. For each KW_GUI - * that you create, you should call KW_Quit(gui) when quitting. KW_GUI - * doesn't take ownership of either the renderer or the tileset. - * - * The tileset will be available to widgets both in the surface and - * texture forms. This is useful if your widget doesn'nt change a lot - * and you want to compose a texture to use always. - * \param renderer A pointer to a KW_RenderDriver. - * \param tileset The tile surface to use as a tileset. - * \returns A initialized KW_GUI instance. - */ -extern DECLSPEC KW_GUI * KW_Init(KW_RenderDriver * renderer, KW_Surface * tileset); - -/** - * \brief Quits this KW_GUI instance and free its resources. - * \details Every pointer passed to any KW_* function will not be free'd - * as KW_GUI doesn't take ownership of them, unless stated otherwise. - * You still have to free them yourself. - * \param gui The KW_GUI instance that is being quitted. - */ -extern DECLSPEC void KW_Quit(KW_GUI * gui); - -/** - * \brief Sets a new KW_RenderDriver for this KW_GUI instance. - * \details If you want to render your GUI in another window, you can pass it's - * renderer to this function. - * \param gui The KW_GUI instance. - * \param render The KW_RenderDriver instance. - */ -extern DECLSPEC void KW_SetRenderer(KW_GUI * gui, KW_RenderDriver * renderer); - -/** - * \brief Returns the current associated renderer with a KW_GUI instance. - * \details This is useful if you are implementing a custom widget and needs to - * render your textures. - * \param gui The KW_GUI instance. - * \return The associated KW_RenderDriver instance. - */ -extern DECLSPEC KW_RenderDriver * KW_GetRenderer(KW_GUI * gui); - -/** - * \brief Set a new tileset surface to be used in this KW_GUI instance. - * \details You may call this function anytime to switch the tileset being used - * to render the widgets. A new texture will be created based on this. - * \param gui The KW_GUI instance to set a new tileset surface. - * \param surface The surface to set. You still have to free the old one. - */ -extern DECLSPEC void KW_SetTilesetSurface(KW_GUI * gui, KW_Surface * tileset); - -/** - * \brief Gets the tileset texture associated with a KW_GUI instance. - * \returns A pointer to a const KW_Texture. You shouldn't modify this - * texture as it is managed by KiWi. - * \param gui The KW_GUI instance to get the tileset from. - */ -extern DECLSPEC KW_Texture * KW_GetTilesetTexture(KW_GUI * gui); - -/** - * \brief Gets the tileset surface associated with a KW_GUI instance. - * \returns A pointer to a KW_RenderDriver. You might want to use this to free - * the surface. - * \param gui The KW_GUI instance to get the tileset from. - */ -extern DECLSPEC KW_Surface * KW_GetTilesetSurface(KW_GUI * gui); - -/** - * \brief Sets a uniform font to be used in label-rendering widgets. - * \details All widgets that needs a font to render text will use by default the font set with this function unless - * you specify otherwise in their respective SetFont calls. - * \param gui The KW_GUI instance to set the font. - * \param font The font to associate with a KW_GUI instance. - */ -extern DECLSPEC void KW_SetFont(KW_GUI * gui, KW_Font * font); - -/** - * \brief Add a function to be called when the current GUI font changes. - * \details If you are rendering text somewhere, you might want to know when - * the font changes to maintain consistency. A new handler will - * be added if the pair (handler, priv) wasn't inserted yet. - * \param gui The KW_GUI instance that will call your handler. - * \param handler The actual handler. - * \param priv Private data that will be passed to the handler. - */ -extern DECLSPEC void KW_AddGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv); - -/** - * \brief Remove a previously added font changed handler. - * \details The pair (handler, priv) will be removed. - * \param gui The KW_GUI instance to remove the handler from. - * \param handler The handler to remove. - * \param priv The private data to match. - */ -extern DECLSPEC void KW_RemoveGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv); - -/** - * \brief Get the current font associated with a KW_GUI instance. - * \details You might want to use this function if you need to render text in a custom widget. - * \param gui The KW_GUI instance to get the font from. - * \return The current font associated with the KW_GUI instance. - */ -extern DECLSPEC KW_Font * KW_GetFont(KW_GUI * gui); - -/** - * \brief Paint all the widgets associated with this GUI. - * \details This will walk the widget tree, painting all of its widgets, from bottom to top. - * \param gui The KW_GUI instance holding the widget tree. - */ -extern DECLSPEC void KW_Paint(KW_GUI * gui); - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_GUI_H +#define KW_GUI_H + +#include "SDL.h" +#include "SDL_ttf.h" + +#include "KW_macros.h" +#include "KW_widget.h" + +/** + * \file KW_gui.h + * + * Main include for the KiWi library. + */ + + +/** + * \mainpage KiWi + * + * http://www.libsdl.org/ + * + * \section intro_sec Introduction + * + * KiWi is a widget-based GUI library for 2D games using SDL2. Its widgets + * are built from a tileset allowing you to customize the looks of your GUI + * by simply changing the source tile set. + * + * You can also create custom widgets. + * + * KiWi is based on SDL2 and SDL2_ttf, requiring these to be present. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The KW_GUI type holds information shared by all widgets. + * \details You need a KW_GUI instance to create widgets. + */ + +typedef void (*KW_OnGUIFontChanged)(KW_GUI * gui, void * data, TTF_Font * font); + +/** + * \brief Initializes a new KW_GUI instance. + * \details Each KW_Widget should be associated with a KW_GUI. For each KW_GUI + * that you create, you should call KW_Quit(gui) when quitting. KW_GUI + * doesn't take ownership of either the renderer or the tileset. + * + * The tileset will be available to widgets both in the surface and + * texture forms. This is useful if your widget doesn'nt change a lot + * and you want to compose a texture to use always. + * \param renderer A pointer to a SDL_Renderer. + * \param tileset The tile surface to use as a tileset. + * \returns A initialized KW_GUI instance. + */ +extern DECLSPEC KW_GUI * KW_Init(SDL_Renderer * renderer, SDL_Surface * tileset); + +/** + * \brief Quits this KW_GUI instance and free its resources. + * \details Every pointer passed to any KW_* function will not be free'd + * as KW_GUI doesn't take ownership of them, unless stated otherwise. + * You still have to free them yourself. + * \param gui The KW_GUI instance that is being quitted. + */ +extern DECLSPEC void KW_Quit(KW_GUI * gui); + +/** + * \brief Sets a new SDL_Renderer for this KW_GUI instance. + * \details If you want to render your GUI in another window, you can pass it's + * renderer to this function. + * \param gui The KW_GUI instance. + * \param render The SDL_Renderer instance. + */ +extern DECLSPEC void KW_SetRenderer(KW_GUI * gui, SDL_Renderer * renderer); + +/** + * \brief Returns the current associated renderer with a KW_GUI instance. + * \details This is useful if you are implementing a custom widget and needs to + * render your textures. + * \param gui The KW_GUI instance. + * \return The associated SDL_Renderer instance. + */ +extern DECLSPEC SDL_Renderer * KW_GetRenderer(KW_GUI * gui); + +/** + * \brief Set a new tileset surface to be used in this KW_GUI instance. + * \details You may call this function anytime to switch the tileset being used + * to render the widgets. A new texture will be created based on this. + * \param gui The KW_GUI instance to set a new tileset surface. + * \param surface The surface to set. You still have to free the old one. + */ +extern DECLSPEC void KW_SetTilesetSurface(KW_GUI * gui, SDL_Surface * tileset); + +/** + * \brief Gets the tileset texture associated with a KW_GUI instance. + * \returns A pointer to a const SDL_Texture. You shouldn't modify this + * texture as it is managed by KiWi. + * \param gui The KW_GUI instance to get the tileset from. + */ +extern DECLSPEC SDL_Texture * KW_GetTilesetTexture(KW_GUI * gui); + +/** + * \brief Gets the tileset surface associated with a KW_GUI instance. + * \returns A pointer to a SDL_Surface. You might want to use this to free + * the surface. + * \param gui The KW_GUI instance to get the tileset from. + */ +extern DECLSPEC SDL_Surface * KW_GetTilesetSurface(KW_GUI * gui); + +/** + * \brief Sets a uniform font to be used in label-rendering widgets. + * \details All widgets that needs a font to render text will use by default the font set with this function unless + * you specify otherwise in their respective SetFont calls. + * \param gui The KW_GUI instance to set the font. + * \param font The font to associate with a KW_GUI instance. + */ +extern DECLSPEC void KW_SetFont(KW_GUI * gui, TTF_Font * font); + +/** + * \brief Add a function to be called when the current GUI font changes. + * \details If you are rendering text somewhere, you might want to know when + * the font changes to maintain consistency. A new handler will + * be added if the pair (handler, priv) wasn't inserted yet. + * \param gui The KW_GUI instance that will call your handler. + * \param handler The actual handler. + * \param priv Private data that will be passed to the handler. + */ +extern DECLSPEC void KW_AddGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv); + +/** + * \brief Remove a previously added font changed handler. + * \details The pair (handler, priv) will be removed. + * \param gui The KW_GUI instance to remove the handler from. + * \param handler The handler to remove. + * \param priv The private data to match. + */ +extern DECLSPEC void KW_RemoveGUIFontChangedHandler(KW_GUI * gui, KW_OnGUIFontChanged handler, void * priv); + +/** + * \brief Get the current font associated with a KW_GUI instance. + * \details You might want to use this function if you need to render text in a custom widget. + * \param gui The KW_GUI instance to get the font from. + * \return The current font associated with the KW_GUI instance. + */ +extern DECLSPEC TTF_Font * KW_GetFont(KW_GUI * gui); + +/** + * \brief Change currently hovered widget + * \details This function notifies previously hovered widget with KW_ON_MOUSELEAVE, changes hovered widget and calls its KW_ON_MOUSEOVER + * \param gui The KW_GUI instance to get the font from. + * \return The current font associated with the KW_GUI instance. + */ +extern DECLSPEC void KW_SetMouseOverWidget(KW_GUI * gui, KW_Widget * widget); + +/** + * \brief Paint all the widgets associated with this GUI. + * \details This will walk the widget tree, painting all of its widgets, from bottom to top. + * \param gui The KW_GUI instance holding the widget tree. + */ +extern DECLSPEC void KW_Paint(KW_GUI * gui); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_gui_internal.h b/src/KW_gui_internal.h index 4db37d4..7fd3f15 100644 --- a/src/KW_gui_internal.h +++ b/src/KW_gui_internal.h @@ -1,46 +1,46 @@ -#ifndef KW_KW_INTERNAL_H -#define KW_KW_INTERNAL_H - -#include "KW_widget.h" -#include "KW_renderdriver.h" - -typedef void (*GUIHandler)(void); - -typedef enum KW_GUIEventHandlerType { - KW_GUI_ONFONTCHANGED, - KW_GUIEVENTHANDLER_TOTAL -} KW_GUIEventHandlerType; - -struct KW_GUI { - KW_Texture * tilesettexture; - KW_Surface * tilesetsurface; - KW_RenderDriver * renderer; - KW_Widget * rootwidget; /* the parent to all parent-less widgets :) */ - KW_Font * font; - - KW_Widget * currentmouseover; /* the current widget that has mouse over */ - KW_Widget * currentfocus; /* which widget was the last focused/clicked */ - KW_Widget * currentdrag; /* the widget where the drag started */ - SDL_bool cursordown; /* indicates whether the cursor is clicked or not */ - - SDL_Event evqueue[1024]; - int evqueuesize; - SDL_mutex * evqueuelock; - - struct { - struct KW_GUICallback { - GUIHandler handler; - void * priv; - } * handlers; - unsigned int count; - } eventhandlers[KW_GUIEVENTHANDLER_TOTAL]; -}; - -void AddGUIHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv); -void RemoveGUItHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv); - - - - - -#endif +#ifndef KW_KW_INTERNAL_H +#define KW_KW_INTERNAL_H + +#include "KW_widget.h" +#include "SDL_ttf.h" + +typedef void (*GUIHandler)(void); + +typedef enum KW_GUIEventHandlerType { + KW_GUI_ONFONTCHANGED, + KW_GUIEVENTHANDLER_TOTAL +} KW_GUIEventHandlerType; + +struct KW_GUI { + SDL_Texture * tilesettexture; + SDL_Surface * tilesetsurface; + SDL_Renderer * renderer; + KW_Widget * rootwidget; /* the parent to all parent-less widgets :) */ + TTF_Font * font; + + KW_Widget * currentmouseover; /* the current widget that has mouse over */ + KW_Widget * currentfocus; /* which widget was the last focused/clicked */ + KW_Widget * currentdrag; /* the widget where the drag started */ + SDL_bool cursordown; /* indicates whether the cursor is clicked or not */ + + SDL_Event evqueue[1024]; + int evqueuesize; + SDL_mutex * evqueuelock; + + struct { + struct KW_GUICallback { + GUIHandler handler; + void * priv; + } * handlers; + unsigned int count; + } eventhandlers[KW_GUIEVENTHANDLER_TOTAL]; +}; + +void AddGUIHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv); +void RemoveGUItHandler(KW_GUI * gui, KW_GUIEventHandlerType handlertype, GUIHandler handler, void * priv); + + + + + +#endif diff --git a/src/KW_label.c b/src/KW_label.c index 8eac58d..0f20cb0 100644 --- a/src/KW_label.c +++ b/src/KW_label.c @@ -1,70 +1,76 @@ -#include "SDL.h" -#include "KW_label.h" -#include "KW_label_internal.h" -#include "KW_tilerenderer.h" -#include "KW_gui.h" - -KW_Widget * KW_CreateLabel(KW_GUI * gui, KW_Widget * parent, const char * text, const KW_Rect * geometry) { - KW_Label * label = calloc(sizeof(KW_Label), 1); - KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_LABEL, geometry, PaintLabel, DestroyLabel, label); - KW_SetLabelText(widget, text); - KW_SetLabelAlignment(widget, KW_LABEL_ALIGN_CENTER, 0, KW_LABEL_ALIGN_MIDDLE, 0); - KW_AddGUIFontChangedHandler(gui, LabelFontChanged, widget); - return widget; -} - -void KW_SetLabelAlignment(KW_Widget * widget, KW_LabelHorizontalAlignment halign, int hoffset, KW_LabelVerticalAlignment valign, int voffset) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - label->halign = halign; - label->hoffset = hoffset; - label->valign = valign; - label->voffset = voffset; -} - - -KW_Font * KW_GetLabelFont(KW_Widget * widget) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - return label->font == NULL ? KW_GetFont(KW_GetGUI(widget)) : label->font; -} - -void KW_SetLabelFont(KW_Widget * widget, KW_Font * font) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - label->font = font; - RenderLabelText(widget); -} - - -void KW_SetLabelText(KW_Widget * widget, const char * text) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - if (label->text != NULL) { - SDL_free(label->text); - } - label->text = SDL_strdup(text); - RenderLabelText(widget); - label->dirty = SDL_TRUE; -} - -void KW_SetLabelStyle(KW_Widget * widget, int style) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - label->style = style; - RenderLabelText(widget); -} - -void KW_SetLabelColor(KW_Widget * widget, KW_Color color) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - label->color = color; - RenderLabelText(widget); -} - -void KW_SetLabelIcon(KW_Widget * widget, const KW_Rect * iconclip) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - if (iconclip == NULL){ - label->iconclip.x = 0; - label->iconclip.y = 0; - label->iconclip.w = 0; - label->iconclip.h = 0; - } else { - label->iconclip = *iconclip; - } -} - +#include "SDL.h" +#include "KW_label.h" +#include "KW_label_internal.h" +#include "KW_textrenderer.h" +#include "KW_tilerenderer.h" +#include "KW_gui.h" + +KW_Widget * KW_CreateLabel(KW_GUI * gui, KW_Widget * parent, const char * text, const SDL_Rect * geometry) { + KW_Label * label = calloc(sizeof(KW_Label), 1); + KW_Widget * widget = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_LABEL, geometry, PaintLabel, DestroyLabel, label); + KW_SetLabelText(widget, text); + KW_SetLabelAlignment(widget, KW_LABEL_ALIGN_CENTER, 0, KW_LABEL_ALIGN_MIDDLE, 0); + KW_AddGUIFontChangedHandler(gui, LabelFontChanged, widget); + return widget; +} + +void KW_SetLabelAlignment(KW_Widget * widget, KW_LabelHorizontalAlignment halign, int hoffset, KW_LabelVerticalAlignment valign, int voffset) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + label->halign = halign; + label->hoffset = hoffset; + label->valign = valign; + label->voffset = voffset; +} + + +TTF_Font * KW_GetLabelFont(KW_Widget * widget) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + return label->font == NULL ? KW_GetFont(KW_GetGUI(widget)) : label->font; +} + +void KW_SetLabelFont(KW_Widget * widget, TTF_Font * font) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + label->font = font; + RenderLabelText(widget); +} + + +void KW_SetLabelText(KW_Widget * widget, const char * text) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + if (label->text != NULL) { + SDL_free(label->text); + } + label->text = SDL_strdup(text); + RenderLabelText(widget); + label->dirty = SDL_TRUE; +} + +const char* KW_GetLabelText(KW_Widget * widget) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + return label->text; +} + +void KW_SetLabelStyle(KW_Widget * widget, int style) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + label->style = style; + RenderLabelText(widget); +} + +void KW_SetLabelColor(KW_Widget * widget, SDL_Color color) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + label->color = color; + RenderLabelText(widget); +} + +void KW_SetLabelIcon(KW_Widget * widget, const SDL_Rect * iconclip) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + if (iconclip == NULL){ + label->iconclip.x = 0; + label->iconclip.y = 0; + label->iconclip.w = 0; + label->iconclip.h = 0; + } else { + label->iconclip = *iconclip; + } +} + diff --git a/src/KW_label.h b/src/KW_label.h index b2da95b..2cb6edb 100644 --- a/src/KW_label.h +++ b/src/KW_label.h @@ -1,143 +1,149 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -/** - * \file KW_label.h - * - * Declares functions for creating and managing labels. - */ - -#ifndef KW_LABEL_H -#define KW_LABEL_H - -#include "KW_widget.h" -#include "SDL_ttf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \name KW_LABEL_STYLE_* - * - * Defines the possible text styles for the label */ -#define KW_LABEL_STYLE_NORMAL 0x00 -#define KW_LABEL_STYLE_BOLD 0x01 -#define KW_LABEL_STYLE_ITALIC 0x02 -#define KW_LABEL_STYLE_UNDERLINE 0x04 -#define KW_LABEL_STYLE_STRIKETHROUGH 0x08 - - -/** - * \brief Possible vertial alignments to align a label. - * \details Text is vertically aligned inside its defined geometry - */ -typedef enum KW_LabelVerticalAlignment { - KW_LABEL_ALIGN_TOP, /** Vertically align label in the top of the geometry. */ - KW_LABEL_ALIGN_MIDDLE, /** Vertically align label in the middle of the geometry. */ - KW_LABEL_ALIGN_BOTTOM /** Vertically align label in the bottom of the geometry. */ -} KW_LabelVerticalAlignment; - -/** - * \brief Possible horizontal alignments to align a label - * \details Text is horizontally aligned inside its defined geometry - */ -typedef enum KW_LabelHorizontalAlignment { - KW_LABEL_ALIGN_LEFT, /** Horizontally align label in the left part of the geometry. */ - KW_LABEL_ALIGN_CENTER, /** Horizontally align label in the center part of the geometry. */ - KW_LABEL_ALIGN_RIGHT /** Horizontally align label in the right part of the geometry. */ -} KW_LabelHorizontalAlignment; - -/** - * \brief Creates a label widget. - * \details The label uses the font specified in the KW_GUI instance unless specified otherwise. - * The geometry of the label is used to align horizontally and vertically the label and also - * to clip its contents if they exceed it. - * \param gui The KW_GUI instance that will hold this widget. - * \param parent The parent widget of this widget. - * \param geometry The relative geometry of this label. - * \return The label instance. - */ -extern DECLSPEC KW_Widget * KW_CreateLabel(KW_GUI * gui, KW_Widget * parent, const char * text, const KW_Rect * geometry); - -/** - * \brief Set the text being rendered in this label. - * \param widget The label widget. - * \param text The text to render. - */ -extern DECLSPEC void KW_SetLabelText(KW_Widget * widget, const char * text); - -/** - * \brief Set the text style for this label. - * \param widget The label widget. - * \param style The style of the text - */ -extern DECLSPEC void KW_SetLabelStyle(KW_Widget * widget, int style); - -/** - * \brief Sets the color of the label text. - * \param widget The label instance. - * \param color The color to assign to the label. - */ -extern DECLSPEC void KW_SetLabelColor(KW_Widget * widget, KW_Color color); - -/** - * \brief Changes the font of the label's text. - * \details Please note that you are responsible for managing the font memory and should free the previous font if its not required anymore. - * \param widget The label widget. - * \param font The font to assign to the label. - */ -extern DECLSPEC void KW_SetLabelFont(KW_Widget * widget, KW_Font * font); - -/** - * \brief Sets label alignment inside a geometry. - * \param widget The widget to ajust the alignment. - * \param halign The horizontal alignment used. - * \param hoffset The horizontal offset to be added to the label position after its aligned. - * \param valign The vertical alignment used. - * \param voffset The vertical offset to be added to the label position after its aligned. - */ -extern DECLSPEC void KW_SetLabelAlignment(KW_Widget * widget, KW_LabelHorizontalAlignment halign, int hoffset, KW_LabelVerticalAlignment valign, int voffset); - -/** - * \brief Display an icon in the left side of the text. - * \details The icon is clipped from the tileset. - * \param widget The label widget to control. - * \param iconclip The clipping rect in the tileset to clip the icon from. Set - * to NULL to remove the icon. - */ -extern DECLSPEC void KW_SetLabelIcon(KW_Widget * widget, const KW_Rect * iconclip); - -/** - * \brief Gets the associated font with a label. - * \param widget The label widget. - * \returns A TTF_Font pointer to the currently label's associated font. - */ -extern DECLSPEC KW_Font * KW_GetLabelFont(KW_Widget * widget); - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/** + * \file KW_label.h + * + * Declares functions for creating and managing labels. + */ + +#ifndef KW_LABEL_H +#define KW_LABEL_H + +#include "KW_widget.h" +#include "SDL_ttf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name KW_LABEL_STYLE_* + * + * Defines the possible text styles for the label */ +#define KW_LABEL_STYLE_NORMAL 0x00 +#define KW_LABEL_STYLE_BOLD 0x01 +#define KW_LABEL_STYLE_ITALIC 0x02 +#define KW_LABEL_STYLE_UNDERLINE 0x04 +#define KW_LABEL_STYLE_STRIKETHROUGH 0x08 + + +/** + * \brief Possible vertial alignments to align a label. + * \details Text is vertically aligned inside its defined geometry + */ +typedef enum KW_LabelVerticalAlignment { + KW_LABEL_ALIGN_TOP, /** Vertically align label in the top of the geometry. */ + KW_LABEL_ALIGN_MIDDLE, /** Vertically align label in the middle of the geometry. */ + KW_LABEL_ALIGN_BOTTOM /** Vertically align label in the bottom of the geometry. */ +} KW_LabelVerticalAlignment; + +/** + * \brief Possible horizontal alignments to align a label + * \details Text is horizontally aligned inside its defined geometry + */ +typedef enum KW_LabelHorizontalAlignment { + KW_LABEL_ALIGN_LEFT, /** Horizontally align label in the left part of the geometry. */ + KW_LABEL_ALIGN_CENTER, /** Horizontally align label in the center part of the geometry. */ + KW_LABEL_ALIGN_RIGHT /** Horizontally align label in the right part of the geometry. */ +} KW_LabelHorizontalAlignment; + +/** + * \brief Creates a label widget. + * \details The label uses the font specified in the KW_GUI instance unless specified otherwise. + * The geometry of the label is used to align horizontally and vertically the label and also + * to clip its contents if they exceed it. + * \param gui The KW_GUI instance that will hold this widget. + * \param parent The parent widget of this widget. + * \param geometry The relative geometry of this label. + * \return The label instance. + */ +extern DECLSPEC KW_Widget * KW_CreateLabel(KW_GUI * gui, KW_Widget * parent, const char * text, const SDL_Rect * geometry); + +/** + * \brief Set the text being rendered in this label. + * \param widget The label widget. + * \param text The text to render. + */ +extern DECLSPEC void KW_SetLabelText(KW_Widget * widget, const char * text); + +/** + * \brief Get the text being rendered in this label. + * \param widget The label widget. + */ +extern DECLSPEC const char* KW_GetLabelText(KW_Widget * widget); + +/** + * \brief Set the text style for this label. + * \param widget The label widget. + * \param style The style of the text + */ +extern DECLSPEC void KW_SetLabelStyle(KW_Widget * widget, int style); + +/** + * \brief Sets the color of the label text. + * \param widget The label instance. + * \param color The color to assign to the label. + */ +extern DECLSPEC void KW_SetLabelColor(KW_Widget * widget, SDL_Color color); + +/** + * \brief Changes the font of the label's text. + * \details Please note that you are responsible for managing the font memory and should free the previous font if its not required anymore. + * \param widget The label widget. + * \param font The font to assign to the label. + */ +extern DECLSPEC void KW_SetLabelFont(KW_Widget * widget, TTF_Font * font); + +/** + * \brief Sets label alignment inside a geometry. + * \param widget The widget to ajust the alignment. + * \param halign The horizontal alignment used. + * \param hoffset The horizontal offset to be added to the label position after its aligned. + * \param valign The vertical alignment used. + * \param voffset The vertical offset to be added to the label position after its aligned. + */ +extern DECLSPEC void KW_SetLabelAlignment(KW_Widget * widget, KW_LabelHorizontalAlignment halign, int hoffset, KW_LabelVerticalAlignment valign, int voffset); + +/** + * \brief Display an icon in the left side of the text. + * \details The icon is clipped from the tileset. + * \param widget The label widget to control. + * \param iconclip The clipping rect in the tileset to clip the icon from. Set + * to NULL to remove the icon. + */ +extern DECLSPEC void KW_SetLabelIcon(KW_Widget * widget, const SDL_Rect * iconclip); + +/** + * \brief Gets the associated font with a label. + * \param widget The label widget. + * \returns A TTF_Font pointer to the currently label's associated font. + */ +extern DECLSPEC TTF_Font * KW_GetLabelFont(KW_Widget * widget); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_label_internal.c b/src/KW_label_internal.c index 1acfda7..0bef40a 100644 --- a/src/KW_label_internal.c +++ b/src/KW_label_internal.c @@ -1,125 +1,127 @@ -#include "KW_label.h" -#include "KW_label_internal.h" - -void LabelFontChanged(KW_GUI * gui, void * data, KW_Font * font) { - RenderLabelText((KW_Widget*)data); -} - -void RenderLabelText(KW_Widget * widget) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - if (label->textrender != NULL) { - KW_ReleaseTexture(KW_GetWidgetRenderer(widget), label->textrender); - } - /* use our own font */ - label->textrender = KW_RenderText(KW_GetWidgetRenderer(widget), KW_GetLabelFont(widget), - label->text, label->color, label->style); - - if (label->textrender != NULL) - KW_GetTextureExtents(KW_GetWidgetRenderer(widget), label->textrender, &(label->textwidth), &(label->textheight)); - else - label->textwidth = label->textheight = 0; -} - -void DestroyLabel(KW_Widget * widget) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - SDL_free(label->text); - KW_ReleaseTexture(KW_GetWidgetRenderer(widget), label->textrender); - free(label); -} - - - -void PaintLabel(KW_Widget * widget) { - KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); - - KW_Rect orig; - KW_Rect dst, icondst; - KW_Rect src, iconsrc; - - KW_RenderDriver * renderer = KW_GetWidgetRenderer(widget); - - /* query actual w and h */ - src.x = src.y = 0; - src.w = label->textwidth; - src.h = label->textheight; - - /* calculate target x/y */ - KW_GetWidgetAbsoluteGeometry(widget, &dst); - orig = dst; - - /* calculate x according to halign */ - switch (label->halign) { - - case KW_LABEL_ALIGN_RIGHT: - dst.x = dst.x + dst.w - src.w; - break; - - case KW_LABEL_ALIGN_CENTER: - dst.x = dst.x + dst.w/2 - src.w/2; - break; - - /* easiest. do nothing */ - case KW_LABEL_ALIGN_LEFT: - default: - break; - }; - - /* apply horizontal offset and icon offset */ - dst.x += label->hoffset; - - /* calculate y according to valign */ - switch (label->valign) { - case KW_LABEL_ALIGN_BOTTOM: - dst.y = dst.y + dst.h - src.h; - break; - - case KW_LABEL_ALIGN_MIDDLE: - dst.y = dst.y + dst.h/2 - src.h/2; - break; - - case KW_LABEL_ALIGN_TOP: - default: - break; - } - - /* apply vertical offset */ - dst.y += label->voffset; - - /* display icon */ - if (!KW_IsRectEmpty(label->iconclip)) { - iconsrc = label->iconclip; - icondst.x = dst.x - (iconsrc.w/2); - dst.x += iconsrc.w/2; - icondst.y = dst.y - (iconsrc.h/2 - src.h/2); /* vertically center icon */ - if (icondst.y < orig.y) { - iconsrc.y += orig.y - icondst.y; - icondst.y += orig.y - icondst.y; - } - - if (icondst.x < orig.x) { - iconsrc.x += orig.x - icondst.x; - icondst.x += orig.x - icondst.x; - } - - if (iconsrc.h > orig.h) iconsrc.h = orig.h; - if (iconsrc.w > orig.w) iconsrc.w = orig.w; - icondst.h = iconsrc.h; - icondst.w = iconsrc.w; - - KW_RenderCopy(renderer, KW_GetWidgetTilesetTexture(widget), &iconsrc, &icondst); - } - /* clip texture so that it doesnt overflow desired maximum geometry */ - if (dst.x < orig.x) src.x = orig.x - dst.x; /* clip left part (centering and right align overflows to the left) */ - if (dst.y < orig.y) src.y = orig.y - dst.y; /* clip top part (middle, bottom align migh overflow top) */ - if (dst.x + src.w > orig.x + orig.w) src.w = orig.w + (orig.x - dst.x) - src.x; /* clip right part (centering, left align) */ - else src.w = src.w - src.x; - if (dst.y + src.h > orig.y + orig.h) src.h = orig.h + (orig.y - dst.y) - src.y; /* clip bottom part (middle, top) */ - else src.h = src.h - src.y; - /* don stretch the image */ - dst.w = src.w; - dst.h = src.h; - dst.x += src.x; - dst.y += src.y; - - KW_RenderCopy(renderer, label->textrender, &src, &dst); -} +#include "KW_label.h" +#include "KW_label_internal.h" +#include "KW_textrenderer.h" + +void LabelFontChanged(KW_GUI * gui, void * data, TTF_Font * font) { + RenderLabelText((KW_Widget*)data); +} + +void RenderLabelText(KW_Widget * widget) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + if (label->textrender != NULL) { + SDL_DestroyTexture(label->textrender); + } + /* use our own font */ + label->textrender = KW_RenderTextLine(KW_GetLabelFont(widget), + KW_GetWidgetRenderer(widget), + label->text, label->color, label->style); + + if (label->textrender != NULL) + SDL_QueryTexture(label->textrender, NULL, NULL, &(label->textwidth), &(label->textheight)); + else + TTF_SizeUTF8(KW_GetLabelFont(widget), "", &(label->textwidth), &(label->textheight)); +} + +void DestroyLabel(KW_Widget * widget) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + SDL_free(label->text); + SDL_DestroyTexture(label->textrender); + free(label); +} + + + +void PaintLabel(KW_Widget * widget) { + KW_Label * label = (KW_Label *) KW_GetWidgetData(widget, KW_WIDGETTYPE_LABEL); + + SDL_Rect orig; + SDL_Rect dst, icondst; + SDL_Rect src, iconsrc; + + SDL_Renderer * renderer = KW_GetWidgetRenderer(widget); + + /* query actual w and h */ + src.x = src.y = 0; + src.w = label->textwidth; + src.h = label->textheight; + + /* calculate target x/y */ + KW_GetWidgetAbsoluteGeometry(widget, &dst); + orig = dst; + + /* calculate x according to halign */ + switch (label->halign) { + + case KW_LABEL_ALIGN_RIGHT: + dst.x = dst.x + dst.w - src.w; + break; + + case KW_LABEL_ALIGN_CENTER: + dst.x = dst.x + dst.w/2 - src.w/2; + break; + + /* easiest. do nothing */ + case KW_LABEL_ALIGN_LEFT: + default: + break; + }; + + /* apply horizontal offset and icon offset */ + dst.x += label->hoffset; + + /* calculate y according to valign */ + switch (label->valign) { + case KW_LABEL_ALIGN_BOTTOM: + dst.y = dst.y + dst.h - src.h; + break; + + case KW_LABEL_ALIGN_MIDDLE: + dst.y = dst.y + dst.h/2 - src.h/2; + break; + + case KW_LABEL_ALIGN_TOP: + default: + break; + } + + /* apply vertical offset */ + dst.y += label->voffset; + + /* display icon */ + if (!SDL_RectEmpty(&label->iconclip)) { + iconsrc = label->iconclip; + icondst.x = dst.x - (iconsrc.w/2); + dst.x += iconsrc.w/2; + icondst.y = dst.y - (iconsrc.h/2 - src.h/2); /* vertically center icon */ + if (icondst.y < orig.y) { + iconsrc.y += orig.y - icondst.y; + icondst.y += orig.y - icondst.y; + } + + if (icondst.x < orig.x) { + iconsrc.x += orig.x - icondst.x; + icondst.x += orig.x - icondst.x; + } + + if (iconsrc.h > orig.h) iconsrc.h = orig.h; + if (iconsrc.w > orig.w) iconsrc.w = orig.w; + icondst.h = iconsrc.h; + icondst.w = iconsrc.w; + + SDL_RenderCopy(renderer, KW_GetWidgetTilesetTexture(widget), &iconsrc, &icondst); + } + /* clip texture so that it doesnt overflow desired maximum geometry */ + if (dst.x < orig.x) src.x = orig.x - dst.x; /* clip left part (centering and right align overflows to the left) */ + if (dst.y < orig.y) src.y = orig.y - dst.y; /* clip top part (middle, bottom align migh overflow top) */ + if (dst.x + src.w > orig.x + orig.w) src.w = orig.w + (orig.x - dst.x) - src.x; /* clip right part (centering, left align) */ + else src.w = src.w - src.x; + if (dst.y + src.h > orig.y + orig.h) src.h = orig.h + (orig.y - dst.y) - src.y; /* clip bottom part (middle, top) */ + else src.h = src.h - src.y; + /* don stretch the image */ + dst.w = src.w; + dst.h = src.h; + dst.x += src.x; + dst.y += src.y; + + SDL_RenderCopy(renderer, label->textrender, &src, &dst); +} diff --git a/src/KW_label_internal.h b/src/KW_label_internal.h index 052a947..911e789 100644 --- a/src/KW_label_internal.h +++ b/src/KW_label_internal.h @@ -1,38 +1,38 @@ -#ifndef KW_LABEL_INTERNAL_H -#define KW_LABEL_INTERNAL_H - -#include "SDL.h" -#include "SDL_ttf.h" -#include "KW_label.h" - -typedef -struct KW_Label { - char * text; - KW_Texture * textrender; - KW_Color color; - int style; - KW_Font * font; - KW_LabelHorizontalAlignment halign; - KW_LabelVerticalAlignment valign; - int hoffset; - int voffset; - unsigned int cursor; - KW_bool showcursor; - KW_bool dirty; - - - unsigned textwidth; - unsigned textheight; - int cursorx; - int cursory; - KW_Rect iconclip; - - int x; -} KW_Label; - -void PaintLabel(KW_Widget * widget); -void RenderLabelText(KW_Widget * widget); -void DestroyLabel(KW_Widget * widget); -void LabelFontChanged(KW_GUI * gui, void * data, KW_Font * font); - -#endif +#ifndef KW_LABEL_INTERNAL_H +#define KW_LABEL_INTERNAL_H + +#include "SDL.h" +#include "SDL_ttf.h" +#include "KW_label.h" + +typedef +struct KW_Label { + char * text; + SDL_Texture * textrender; + SDL_Color color; + int style; + TTF_Font * font; + KW_LabelHorizontalAlignment halign; + KW_LabelVerticalAlignment valign; + int hoffset; + int voffset; + unsigned int cursor; + SDL_bool showcursor; + SDL_bool dirty; + + + int textwidth; + int textheight; + int cursorx; + int cursory; + SDL_Rect iconclip; + + int x; +} KW_Label; + +void PaintLabel(KW_Widget * widget); +void RenderLabelText(KW_Widget * widget); +void DestroyLabel(KW_Widget * widget); +void LabelFontChanged(KW_GUI * gui, void * data, TTF_Font * font); + +#endif diff --git a/src/KW_macros.h b/src/KW_macros.h index 701aa72..f62a97a 100644 --- a/src/KW_macros.h +++ b/src/KW_macros.h @@ -1,62 +1,62 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_MACROS_H -#define KW_MACROS_H - -/* this file was shamelessly copied from SDL */ - -/* Some compilers use a special export keyword */ -#ifndef DECLSPEC -# if defined(__WIN32__) -# ifdef __BORLANDC__ -# ifdef KiWi_EXPORTS -# define DECLSPEC -# else -# define DECLSPEC __declspec(dllimport) -# endif -# else -# define DECLSPEC __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && __GNUC__ >= 4 -# define DECLSPEC __attribute__ ((visibility("default"))) -# elif defined(__GNUC__) && __GNUC__ >= 2 -# define DECLSPEC __declspec(dllexport) -# else -# define DECLSPEC -# endif -# endif -#endif - -/* By default SDL uses the C calling convention */ -#ifndef KIWICALL -#if defined(__WIN32__) && !defined(__GNUC__) -#define KIWICALL __cdecl -#else -#define KIWICALL -#endif -#endif /* KIWICALL */ - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_MACROS_H +#define KW_MACROS_H + +/* this file was shamelessly copied from SDL */ + +/* Some compilers use a special export keyword */ +#ifndef DECLSPEC +# if defined(__WIN32__) +# ifdef __BORLANDC__ +# ifdef KiWi_EXPORTS +# define DECLSPEC +# else +# define DECLSPEC __declspec(dllimport) +# endif +# else +# define DECLSPEC __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && __GNUC__ >= 4 +# define DECLSPEC __attribute__ ((visibility("default"))) +# elif defined(__GNUC__) && __GNUC__ >= 2 +# define DECLSPEC __declspec(dllexport) +# else +# define DECLSPEC +# endif +# endif +#endif + +/* By default SDL uses the C calling convention */ +#ifndef KIWICALL +#if defined(__WIN32__) && !defined(__GNUC__) +#define KIWICALL __cdecl +#else +#define KIWICALL +#endif +#endif /* KIWICALL */ + +#endif diff --git a/src/KW_renderdriver.c b/src/KW_renderdriver.c deleted file mode 100644 index 48d2ab2..0000000 --- a/src/KW_renderdriver.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "KW_renderdriver.h" - -void KW_BlitSurface(KW_RenderDriver * driver, KW_Surface * src, const KW_Rect * srcRect, KW_Surface * dst, const KW_Rect * dstRect) { - driver->blitSurface(driver, src, srcRect, dst, dstRect); -} - -KW_Surface * KW_CreateSurface(KW_RenderDriver * driver, unsigned width, unsigned height) { - return driver->createSurface(driver, width, height); -} - -void KW_GetSurfaceExtents(KW_RenderDriver * driver, const KW_Surface * surface, unsigned * width, unsigned * height) { - driver->getSurfaceExtents(driver, surface, width, height); -} - -void KW_GetTextureExtents(KW_RenderDriver * driver, KW_Texture * texture, unsigned * width, unsigned * height) { - driver->getTextureExtents(driver, texture, width, height); -} - -void KW_RenderCopy(KW_RenderDriver * driver, KW_Texture * src, const KW_Rect * clip, const KW_Rect * dstRect) { - driver->renderCopy(driver, src, clip, dstRect); -} - -KW_Surface * KW_RenderText(KW_RenderDriver * driver, KW_Font * font, const char * text, KW_Color color, KW_RenderDriver_TextStyle style) { - return driver->renderText(driver, font, text, color, style); -} - -KW_Font * KW_LoadFont(KW_RenderDriver * driver, const char * fontFile, unsigned ptSize) { - return driver->loadFont(driver, fontFile, ptSize); -} - -KW_Texture * KW_CreateTexture(KW_RenderDriver * driver, KW_Surface * surface) { - return driver->createTexture(driver, surface); -} - -KW_Texture * KW_LoadTexture(KW_RenderDriver * driver, const char * file) { - return driver->loadTexture(driver, file); -} - -KW_Surface * KW_LoadSurface(KW_RenderDriver * driver, const char * file) { - return driver->loadSurface(driver, file); -} - -void KW_ReleaseTexture(KW_RenderDriver * driver, KW_Texture * texture) { - driver->releaseTexture(driver, texture); -} - -void KW_ReleaseSurface(KW_RenderDriver * driver, KW_Surface * surface) { - driver->releaseSurface(driver, surface); -} - -void KW_ReleaseFont(KW_RenderDriver * driver, KW_Font * font) { - driver->releaseFont(driver, font); -} - -void KW_SetClipRect(KW_RenderDriver * driver, const KW_Rect * clip, int force) { - driver->setClipRect(driver, clip, force); -} - -void KW_GetClipRect(KW_RenderDriver * driver, KW_Rect * clip) { - driver->getClipRect(driver, clip); -} diff --git a/src/KW_renderdriver.h b/src/KW_renderdriver.h deleted file mode 100644 index 630ca7b..0000000 --- a/src/KW_renderdriver.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef RENDERDRIVER_H -#define RENDERDRIVER_H - -/** - * \file KW_renderdriver.h - * - * Declares the RenderDriver API to be implemented to create new Render Drivers - **/ - -#include "KW_macros.h" - -typedef void KW_Texture; -typedef void KW_Font; -typedef void KW_Surface; - -typedef struct KW_Rect { - unsigned int x; - unsigned int y; - unsigned int w; - unsigned int h; -} KW_Rect; - -#define KW_IsRectEmpty(r) \ - (((r.x) > 0) && ((r.y) > 0) && ((r.w) > 0) && ((r.h) > 0)) - -/** - * \brief Holds a color in the RGBA format - **/ -typedef struct KW_Color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -} KW_Color; - -typedef struct KW_RenderDriver KW_RenderDriver; - -/** - * \brief Defines how text should be rendered - **/ -typedef enum KW_RenderDriver_TextStyle { - KW_TTF_STYLE_NORMAL = 0x00, - KW_TTF_STYLE_BOLD = 0x01, - KW_TTF_STYLE_ITALIC = 0x02, - KW_TTF_STYLE_UNDERLINE = 0x04, - KW_TTF_STYLE_STRIKETHROUGH = 0x08 -} KW_RenderDriver_TextStyle; - - -/** - * \brief Declares the prototype for a RenderCopy function - * \details A RenderCopy function deals with Textures that are possibly in GPU's RAM. - * It should be able to take a src texture and render it, applying clipping with clipRect - * and scaling with dstRect. - * \param driver the RenderDriver that will render this texture. - * \param src the source texture. - * \param clip the clipping rectangle for the source texture (in pixels) - * \param dstRect the destination rect. If different that clipping rectangle, it should scale to fit. - */ -typedef void (*KW_RenderCopyFunction)(KW_RenderDriver * driver, KW_Texture * src, const KW_Rect * clip, const KW_Rect * dstRect); - -/** - * \brief Declares the prototype for a RenderText function. - * \details A RenderText function should be able to receive a font, a textline and a color and - * it should be able to produce a surface (pixeldata in CPU's memory) to be later transformed - * into a texture. - * \param driver the RenderDriver that will render this texture. - * \param font the font to use when rendering text. - * \param color the color that should be used. - * \param style the KW_RenderDriver_TextStyle style to apply. - * \return a KW_Surface to be later used as a texture. - */ -typedef KW_Surface * (*KW_RenderTextFunction)(KW_RenderDriver * driver, KW_Font * font, const char * text, KW_Color color, KW_RenderDriver_TextStyle style); - -/** - * \brief Declares the prototype for a LoadFont function. - * \details LoadFont should be able to load a fontFile with the specified point size. - * \param driver the RenderDriver that will render this texture. - * \param fontFile the file containing the font (usually .ttf) - * \return a KW_Font suitable to use with KW_RenderText - */ -typedef KW_Font * (*KW_LoadFontFunction)(KW_RenderDriver * driver, const char * fontFile, unsigned ptSize); - -/** - * \brief Declares the prototype for a CreateTexture function. - * \details CreateTexture should be able to create a KW_Texture from a KW_Surface. - * \param driver the RenderDriver that will render this texture. - * \param src the source KW_Surface. - * \return a KW_Texture in suitable to use with KW_RenderCopy - */ -typedef KW_Texture * (*KW_CreateTextureFunction)(KW_RenderDriver * driver, KW_Surface * src); - - -/** - * \brief Declares the prototype for a LoadTexture function. - * \details LoadTexture should be able to create a KW_Texture from a file. - * \param driver the RenderDriver that will load this texture. - * \param file the file name with the pixeldata. - * \return a KW_Texture suitable to use with KW_RenderCopy - */ -typedef KW_Texture * (*KW_LoadTextureFunction)(KW_RenderDriver * driver, const char * file); - -/** - * \brief Declares the prototype for a LoadSurface function. - * \details LoadSurface should be able to create a KW_Surface from a file. - * \param driver the RenderDriver that will load this surface. - * \param file the file name with the pixeldata. - * \return a KW_Surface. - */ -typedef KW_Surface * (*KW_LoadSurfaceFunction)(KW_RenderDriver * driver, const char * file); -typedef void (*KW_ReleaseTextureFunction)(KW_RenderDriver * driver, KW_Texture * texture); -typedef void (*KW_ReleaseSurfaceFunction)(KW_RenderDriver * driver, KW_Surface * surface); -typedef void (*KW_ReleaseFontFunction)(KW_RenderDriver * driver, KW_Font * font); -typedef KW_Surface * (*KW_CreateSurfaceFunction)(KW_RenderDriver * driver, unsigned width, unsigned height); -typedef void (*KW_GetSurfaceExtentsFunction)(KW_RenderDriver * driver, const KW_Surface * surface, unsigned * width, unsigned * height); -typedef void (*KW_GetTextureExtentsFunction)(KW_RenderDriver * driver, KW_Texture * texture, unsigned * width, unsigned * height); -typedef void (*KW_BlitSurfaceFunction)(KW_RenderDriver * driver, KW_Surface * src, const KW_Rect * srcRect, KW_Surface * dst, const KW_Rect * dstRect); -typedef void (*KW_SetClipRectFunction)(KW_RenderDriver * driver, const KW_Rect * clip, int force); -typedef void (*KW_GetClipRectFunction)(KW_RenderDriver * driver, KW_Rect * clip); - -struct KW_RenderDriver { - KW_RenderCopyFunction renderCopy; - KW_RenderTextFunction renderText; - KW_LoadFontFunction loadFont; - KW_CreateTextureFunction createTexture; - KW_CreateSurfaceFunction createSurface; - KW_LoadTextureFunction loadTexture; - KW_LoadSurfaceFunction loadSurface; - - KW_GetSurfaceExtentsFunction getSurfaceExtents; - KW_GetTextureExtentsFunction getTextureExtents; - KW_BlitSurfaceFunction blitSurface; - - KW_ReleaseTextureFunction releaseTexture; - KW_ReleaseSurfaceFunction releaseSurface; - KW_ReleaseFontFunction releaseFont; - - KW_SetClipRectFunction setClipRect; - KW_GetClipRectFunction getClipRect; - - void * priv; -}; - -extern DECLSPEC void KW_BlitSurface(KW_RenderDriver * driver, KW_Surface * src, const KW_Rect * srcRect, KW_Surface * dst, const KW_Rect * dstRect); -extern DECLSPEC KW_Surface * KW_CreateSurface(KW_RenderDriver * driver, unsigned width, unsigned height); -extern DECLSPEC void KW_GetSurfaceExtents(KW_RenderDriver * driver, const KW_Surface * surface, unsigned * width, unsigned * height); -extern DECLSPEC void KW_GetTextureExtents(KW_RenderDriver * driver, KW_Texture * texture, unsigned * width, unsigned * height); -extern DECLSPEC void KW_RenderCopy(KW_RenderDriver * driver, KW_Texture * src, const KW_Rect * clip, const KW_Rect * dstRect); -extern DECLSPEC KW_Surface * KW_RenderText(KW_RenderDriver * driver, KW_Font * font, const char * text, KW_Color color, KW_RenderDriver_TextStyle style); -extern DECLSPEC KW_Font * KW_LoadFont(KW_RenderDriver * driver, const char * fontFile, unsigned ptSize); -extern DECLSPEC KW_Texture * KW_CreateTexture(KW_RenderDriver * driver, KW_Surface * surface); -extern DECLSPEC KW_Texture * KW_LoadTexture(KW_RenderDriver * driver, const char * file); -extern DECLSPEC KW_Surface * KW_LoadSurface(KW_RenderDriver * driver, const char * file); -extern DECLSPEC void KW_ReleaseTexture(KW_RenderDriver * driver, KW_Texture * texture); -extern DECLSPEC void KW_ReleaseSurface(KW_RenderDriver * driver, KW_Surface * surface); -extern DECLSPEC void KW_ReleaseFont(KW_RenderDriver * driver, KW_Font * font); -extern DECLSPEC void KW_GetClipRect(KW_RenderDriver * driver, KW_Rect * clip); -extern DECLSPEC void KW_SetClipRect(KW_RenderDriver * driver, const KW_Rect * clip, int force); - -#endif diff --git a/src/KW_renderdriver_sdl2.c b/src/KW_renderdriver_sdl2.c deleted file mode 100644 index 4a5cb5e..0000000 --- a/src/KW_renderdriver_sdl2.c +++ /dev/null @@ -1,208 +0,0 @@ -#include "KW_renderdriver_sdl2.h" -#include "KW_renderdriver.h" -#include "KW_widget.h" -#include "SDL.h" -#include "SDL_ttf.h" -#include "SDL_image.h" - - -typedef struct KWSDL { - SDL_Renderer * renderer; - SDL_Window * window; -} KWSDL; - -static void KWSDL_renderCopy(KW_RenderDriver * driver, KW_Texture * texture, const KW_Rect * src, const KW_Rect * dst); -static KW_Texture * KWSDL_renderText(KW_RenderDriver * driver, KW_Font * font, const char * text, KW_Color color, KW_RenderDriver_TextStyle style); -static KW_Font * KWSDL_loadFont(KW_RenderDriver * driver, const char * font, unsigned ptSize); -static KW_Font * KWSDL_createTexture(KW_RenderDriver * driver, KW_Surface * surface); -static KW_Surface * KWSDL_createRGBA32Surface(KW_RenderDriver * driver, unsigned width, unsigned height); -static KW_Texture * KWSDL_loadTexture(KW_RenderDriver * driver, const char * texturefile); -static KW_Surface * KWSDL_loadSurface(KW_RenderDriver * driver, const char * texturefile); -static void KWSDL_getSurfaceExtents(KW_RenderDriver * driver, const KW_Surface * surface, unsigned * width, unsigned * height); -static void KWSDL_getTextureExtents(KW_RenderDriver * driver, KW_Texture * texture, unsigned * width, unsigned * height); -static void KWSDL_releaseTexture(KW_RenderDriver * driver, KW_Texture * texture); -static void KWSDL_releaseFont(KW_RenderDriver * driver, KW_Font * font); -static void KWSDL_blitSurface(KW_RenderDriver * driver, KW_Surface * src, const KW_Rect * srcRect, KW_Surface * dst, const KW_Rect * dstRect); -static void KWSDL_releaseSurface(KW_RenderDriver * driver, KW_Surface * font); -static void KWSDL_setClipRect(KW_RenderDriver * driver, const KW_Rect * clip, int force); -static void KWSDL_getClipRect(KW_RenderDriver * driver, KW_Rect * clip); - -struct KW_RenderDriver * KW_CreateSDL2RenderDriver(SDL_Renderer * renderer, SDL_Window * window) { - struct KWSDL * kwsdl = calloc(sizeof(*kwsdl), 1); - struct KW_RenderDriver * rd = calloc(sizeof(*rd), 1); - - TTF_Init(); - - kwsdl->renderer = renderer; - kwsdl->window = window; - - rd->renderCopy = KWSDL_renderCopy; - rd->renderText = KWSDL_renderText; - rd->loadFont = KWSDL_loadFont; - rd->createTexture = KWSDL_createTexture; - rd->createSurface = KWSDL_createRGBA32Surface; - rd->loadTexture = KWSDL_loadTexture; - rd->loadSurface = KWSDL_loadSurface; - rd->getSurfaceExtents = KWSDL_getSurfaceExtents; - rd->getTextureExtents = KWSDL_getTextureExtents; - rd->blitSurface = KWSDL_blitSurface; - rd->releaseFont = KWSDL_releaseFont; - rd->releaseSurface = KWSDL_releaseSurface; - rd->releaseTexture = KWSDL_releaseTexture; - rd->setClipRect = KWSDL_setClipRect; - rd->getClipRect = KWSDL_getClipRect; - - rd->priv = kwsdl; - return rd; -} - -static KW_Texture * KWSDL_createTexture(KW_RenderDriver * driver, KW_Surface * surface) { - KWSDL * kwsdl = (KWSDL *) driver->priv; - SDL_Texture * t = SDL_CreateTextureFromSurface(kwsdl->renderer, (SDL_Surface *)surface); - SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND); - return t; -} - -static KW_Surface * KWSDL_createRGBA32Surface(KW_RenderDriver * driver, unsigned width, unsigned height) { - unsigned rmask, gmask, bmask, amask; - SDL_Surface * s; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - s = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask); - SDL_SetSurfaceBlendMode(s, SDL_BLENDMODE_NONE); - return s; -} - -static KW_Font * KWSDL_loadFont(KW_RenderDriver * driver, const char * font, unsigned ptSize) { - TTF_Font * f = TTF_OpenFont(font, ptSize); - (void)driver; - if (f == NULL) { - fprintf(stderr, "KW_RenderDriver_SDL: Could not load font %s: %s\n", font, TTF_GetError()); - return NULL; - } - return f; -} - -static KW_Surface * KWSDL_loadSurface(KW_RenderDriver * driver, const char * texturefile) { - SDL_Surface * s = IMG_Load(texturefile); - if (s == NULL) { - fprintf(stderr, "KW_RenderDriver_SDL: Could not load texture %s: %s\n", texturefile, IMG_GetError()); - return NULL; - } - SDL_SetSurfaceBlendMode(s, SDL_BLENDMODE_NONE); - return s; -} - -static void KWSDL_getSurfaceExtents(KW_RenderDriver * driver, const KW_Surface * surface, unsigned * width, unsigned * height) { - (void)driver; - if (width) *width = ((SDL_Surface*)surface)->w; - if (height) *height = ((SDL_Surface*)surface)->h; -} - -static void KWSDL_getTextureExtents(KW_RenderDriver * driver, KW_Surface * texture, unsigned * width, unsigned * height) { - int w, h; - (void)driver; - SDL_QueryTexture(texture, NULL, NULL, &w, &h); - *width = w; *height = h; -} - -static void KWSDL_blitSurface(KW_RenderDriver * driver, KW_Surface * src, const KW_Rect * srcRect, KW_Surface * dst, const KW_Rect * dstRect) { - SDL_Rect s, d; - s.x = srcRect->x; s.y = srcRect->y; s.w = srcRect->w; s.h = srcRect->h; - d.x = dstRect->x; d.y = dstRect->y; d.w = dstRect->w; d.h = dstRect->h; - SDL_BlitSurface((SDL_Surface *) src, &s, (SDL_Surface *) dst, &d); -} - -static KW_Texture * KWSDL_loadTexture(KW_RenderDriver * driver, const char * texturefile) { - KWSDL * kwsdl = (KWSDL *) driver->priv; - SDL_Texture * t = IMG_LoadTexture(kwsdl->renderer, texturefile); - if (t == NULL) { - fprintf(stderr, "KW_RenderDriver_SDL: Could not load texture %s: %s\n", texturefile, IMG_GetError()); - return NULL; - } - SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND); - - return t; -} - -static KW_Texture * KWSDL_renderText(KW_RenderDriver * driver, KW_Font * font, const char * text, KW_Color color, KW_RenderDriver_TextStyle style) { - KWSDL * kwsdl = (KWSDL *) driver->priv; - int previousstyle; - SDL_Color sdlcolor; - SDL_Surface * textsurface; - SDL_Texture * ret; - - sdlcolor.r = color.r, sdlcolor.g = color.g, sdlcolor.b = color.b, sdlcolor.a = color.a; - if (font == NULL || text == NULL) - return NULL; - - previousstyle = TTF_GetFontStyle(font); - TTF_SetFontStyle(font, style); - textsurface = TTF_RenderUTF8_Blended(font, text, sdlcolor); - ret = SDL_CreateTextureFromSurface(kwsdl->renderer, textsurface); - SDL_FreeSurface(textsurface); - TTF_SetFontStyle(font, previousstyle); - return ret; -} - -static void KWSDL_releaseTexture(KW_RenderDriver * driver, KW_Texture * texture) { - (void)driver; - SDL_DestroyTexture(texture); -} - -static void KWSDL_releaseSurface(KW_RenderDriver * driver, KW_Surface * surface) { - (void)driver; - SDL_FreeSurface(surface); -} - -static void KWSDL_releaseFont(KW_RenderDriver * driver, KW_Font * font) { - (void)driver; - TTF_CloseFont(font); -} - -static void KWSDL_renderCopy(KW_RenderDriver * driver, KW_Texture * texture, const KW_Rect * src, const KW_Rect * dst) { - KWSDL * kwsdl = (KWSDL *) driver->priv; - SDL_Rect srcRect, dstRect; - if (src) { srcRect.x = src->x; srcRect.y = src->y; srcRect.w = src->w; srcRect.h = src->h; } - if (dst) { dstRect.x = dst->x; dstRect.y = dst->y; dstRect.w = dst->w; dstRect.h = dst->h; } - SDL_RenderCopy(kwsdl->renderer, texture, src ? &srcRect : NULL, dst? &dstRect : NULL); -} - -static void KWSDL_setClipRect(KW_RenderDriver * driver, const KW_Rect * clip, int force) { - SDL_Renderer * renderer = ((KWSDL *)driver->priv)->renderer; - SDL_Rect viewport, cliprect; - static SDL_RendererInfo info; - static int isopengl = -1; - cliprect.x = clip->x; cliprect.y = clip->y; cliprect.w = clip->w; cliprect.h = clip->h; - if (isopengl < 0) { - SDL_GetRendererInfo(renderer, &info); - isopengl = (strcmp(info.name, "opengl") >= 0) ? 1 : 0; - } - - if (isopengl && !force) { - /* fix for SDL buggy opengl scissor test. See SDL bug 2269. - * Not sure about other renderers. */ - SDL_RenderGetViewport(renderer, &viewport); - cliprect.x += viewport.x; cliprect.y -= viewport.y; - } - - if (KW_IsRectEmpty((*clip))) - SDL_RenderSetClipRect(renderer, NULL); - else - SDL_RenderSetClipRect(renderer, &cliprect); -} - -static void KWSDL_getClipRect(KW_RenderDriver * driver, KW_Rect * clip) { - SDL_Rect c; - SDL_RenderGetClipRect(((KWSDL *)driver->priv)->renderer, &c); - clip->x = c.x; clip->y = c.y; clip->w = c.w; clip->h = c.h; -} diff --git a/src/KW_renderdriver_sdl2.h b/src/KW_renderdriver_sdl2.h deleted file mode 100644 index 59bffa0..0000000 --- a/src/KW_renderdriver_sdl2.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef KW_RENDERDRIVER_SDL2 -#define KW_RENDERDRIVER_SDL2 - -struct SDL_Renderer; -struct SDL_Window; - -#include "KW_macros.h" - -extern DECLSPEC struct KW_RenderDriver * KW_CreateSDL2RenderDriver(struct SDL_Renderer * renderer, struct SDL_Window * window); - -#endif - diff --git a/src/KW_scrollbox.c b/src/KW_scrollbox.c index d7e9fba..26b5545 100644 --- a/src/KW_scrollbox.c +++ b/src/KW_scrollbox.c @@ -1,81 +1,111 @@ -#include "KW_scrollbox.h" -#include "KW_scrollbox_internal.h" -#include "KW_tilerenderer.h" -#include "KW_button.h" - -KW_Widget * KW_CreateScrollbox(KW_GUI * gui, KW_Widget * parent, const KW_Rect * geometry) { - /* creates root scrollbox widget */ - KW_Scrollbox * scrollbox = AllocScrollbox(); - KW_Widget * outer, * inner; - KW_Widget * root = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_SCROLLBOX, - geometry, PaintScrollboxFrame, - DestroyScrollboxFrame, scrollbox); - - KW_Rect areageom = *geometry; - KW_Rect buttongeom; - /* Ignore borders */ - areageom.x = TILESIZE; - areageom.y = TILESIZE; - areageom.w = geometry->w - TILESIZE * 4; - areageom.h = geometry->h - TILESIZE * 4; - outer = KW_CreateWidget(gui, root, KW_WIDGETTYPE_NONE, &areageom, NULL, NULL, scrollbox); - areageom.x = 0; areageom.y = 0; /* areageom.h = 0; areageom.w = 0; */ - inner = KW_CreateWidget(gui, outer, KW_WIDGETTYPE_NONE, &areageom, NULL, NULL, scrollbox); - KW_SetWidgetGeometry(inner, &areageom); - KW_SetClipChildrenWidgets(outer, SDL_TRUE); - KW_AddWidgetKeyUpHandler(root, ScrollboxKeyUp); - KW_AddWidgetKeyUpHandler(inner, ScrollboxKeyUp); - - scrollbox->outer = outer; - scrollbox->inner = inner; - scrollbox->root = root; - - buttongeom.x = geometry->w - TILESIZE * 3; - buttongeom.y = geometry->y + TILESIZE; - buttongeom.w = TILESIZE*2; - buttongeom.h = TILESIZE*2; - scrollbox->vscroll = KW_CreateButton(gui, root, "", &buttongeom); - - buttongeom.x = TILESIZE; - buttongeom.y = geometry->h - TILESIZE * 3; - buttongeom.w = TILESIZE*2; - buttongeom.h = TILESIZE*2; - scrollbox->hscroll = KW_CreateButton(gui, root, "", &buttongeom); - - KW_AddWidgetChildrenChangeHandler(root, ChildrenChange); - - KW_AddWidgetDragHandler(scrollbox->vscroll, VerticalBarDrag); - KW_AddWidgetDragHandler(scrollbox->hscroll, HorizontalBarDrag); - - KW_AddWidgetGeometryChangeHandler(root, RootScrollboxGeometryChange); - RenderScrollboxFrame(scrollbox); - return scrollbox->root; -} - -void KW_ScrollboxVerticalScroll(KW_Widget * scrollbox, int amount) { - /* remember we are dealing with the *outer* widget */ - KW_Rect geom, outer; - KW_Scrollbox * sb = KW_GetWidgetData(scrollbox, KW_WIDGETTYPE_SCROLLBOX); - KW_GetWidgetGeometry(sb->inner, &geom); - KW_GetWidgetGeometry(sb->outer, &outer); - - if (sb->innercomposite.y + amount > 0) amount = -sb->innercomposite.y; - if (sb->innercomposite.y + sb->innercomposite.h + amount < outer.h) - amount = outer.h - (sb->innercomposite.y + sb->innercomposite.h); - - geom.y += amount; - KW_SetWidgetGeometry(sb->inner, &geom); -} - -void KW_ScrollboxHorizontalScroll(KW_Widget * scrollbox, int amount) { - /* remember we are dealing with the *outer* widget */ - KW_Rect geom, outer; - KW_Scrollbox * sb = KW_GetWidgetData(scrollbox, KW_WIDGETTYPE_SCROLLBOX); - KW_GetWidgetGeometry(sb->inner, &geom); - KW_GetWidgetGeometry(sb->outer, &outer); - if (sb->innercomposite.x + amount > 0) amount = -sb->innercomposite.x; - if (sb->innercomposite.x + sb->innercomposite.w + amount < outer.w) - amount = outer.w - (sb->innercomposite.x + sb->innercomposite.w); - geom.x += amount; - KW_SetWidgetGeometry(sb->inner, &geom); -} +#include "KW_scrollbox.h" +#include "KW_scrollbox_internal.h" +#include "KW_tilerenderer.h" +#include "KW_button.h" + +KW_Widget * KW_CreateScrollbox(KW_GUI * gui, KW_Widget * parent, const SDL_Rect * geometry) { + /* creates root scrollbox widget */ + KW_Scrollbox * scrollbox = AllocScrollbox(); + KW_Widget * outer, * inner; + KW_Widget * root = KW_CreateWidget(gui, parent, KW_WIDGETTYPE_SCROLLBOX, + geometry, PaintScrollboxFrame, + DestroyScrollboxFrame, scrollbox); + + SDL_Rect areageom = *geometry; + SDL_Rect buttongeom; + /* Ignore borders */ + areageom.x = TILESIZE; + areageom.y = TILESIZE; + areageom.w = geometry->w - TILESIZE * 4; + areageom.h = geometry->h - TILESIZE * 4; + outer = KW_CreateWidget(gui, root, KW_WIDGETTYPE_NONE, &areageom, NULL, NULL, scrollbox); + areageom.x = 0; areageom.y = 0; /* areageom.h = 0; areageom.w = 0; */ + inner = KW_CreateWidget(gui, outer, KW_WIDGETTYPE_NONE, &areageom, NULL, NULL, scrollbox); + KW_SetWidgetGeometry(inner, &areageom); + KW_SetClipChildrenWidgets(outer, SDL_TRUE); + KW_AddWidgetKeyUpHandler(root, ScrollboxKeyUp); + KW_AddWidgetKeyUpHandler(inner, ScrollboxKeyUp); + + scrollbox->outer = outer; + scrollbox->inner = inner; + scrollbox->root = root; + + buttongeom.x = geometry->w - TILESIZE * 3; + buttongeom.y = geometry->y + TILESIZE; + buttongeom.w = TILESIZE*2; + buttongeom.h = TILESIZE*2; + scrollbox->vscroll = KW_CreateButton(gui, root, "", &buttongeom); + + buttongeom.x = TILESIZE; + buttongeom.y = geometry->h - TILESIZE * 3; + buttongeom.w = TILESIZE*2; + buttongeom.h = TILESIZE*2; + scrollbox->hscroll = KW_CreateButton(gui, root, "", &buttongeom); + + KW_AddWidgetChildrenChangeHandler(root, ChildrenChange); + + KW_AddWidgetDragHandler(scrollbox->vscroll, VerticalBarDrag); + KW_AddWidgetDragHandler(scrollbox->hscroll, HorizontalBarDrag); + + KW_AddWidgetGeometryChangeHandler(root, RootScrollboxGeometryChange); + RenderScrollboxFrame(scrollbox); + KW_ScrollboxSetType(scrollbox->root, KW_SCROLLBOX_BOOTH); + return scrollbox->root; +} + +void KW_ScrollboxVerticalScroll(KW_Widget * scrollbox, int amount) { + /* remember we are dealing with the *outer* widget */ + SDL_Rect geom, outer; + KW_Scrollbox * sb = KW_GetWidgetData(scrollbox, KW_WIDGETTYPE_SCROLLBOX); + KW_GetWidgetGeometry(sb->inner, &geom); + KW_GetWidgetGeometry(sb->outer, &outer); + + if (sb->innercomposite.y + amount > 0) amount = -sb->innercomposite.y; + if (sb->innercomposite.y + sb->innercomposite.h + amount < outer.h) + amount = outer.h - (sb->innercomposite.y + sb->innercomposite.h); + + geom.y += amount; + KW_SetWidgetGeometry(sb->inner, &geom); +} + +void KW_ScrollboxHorizontalScroll(KW_Widget * scrollbox, int amount) { + /* remember we are dealing with the *outer* widget */ + SDL_Rect geom, outer; + KW_Scrollbox * sb = KW_GetWidgetData(scrollbox, KW_WIDGETTYPE_SCROLLBOX); + KW_GetWidgetGeometry(sb->inner, &geom); + KW_GetWidgetGeometry(sb->outer, &outer); + if (sb->innercomposite.x + amount > 0) amount = -sb->innercomposite.x; + if (sb->innercomposite.x + sb->innercomposite.w + amount < outer.w) + amount = outer.w - (sb->innercomposite.x + sb->innercomposite.w); + geom.x += amount; + KW_SetWidgetGeometry(sb->inner, &geom); +} + +void KW_ScrollboxSetType(KW_Widget * scrollbox, KW_ScrollboxType type) { + KW_Scrollbox * sb = KW_GetWidgetData(scrollbox, KW_WIDGETTYPE_SCROLLBOX); + sb->scrolltype = type; + switch(sb->scrolltype) { + + default: + case KW_SCROLLBOX_BOOTH: + KW_SetWidgetHidden(sb->vscroll, SDL_FALSE); + KW_SetWidgetHidden(sb->hscroll, SDL_FALSE); + KW_DisableWidgetHint(sb->vscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + KW_DisableWidgetHint(sb->hscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + break; + + case KW_SCROLLBOX_HORIZONTAL: + KW_SetWidgetHidden(sb->vscroll, SDL_TRUE); + KW_SetWidgetHidden(sb->hscroll, SDL_FALSE); + KW_EnableWidgetHint(sb->vscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + KW_DisableWidgetHint(sb->hscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + break; + + case KW_SCROLLBOX_VERTICAL: + KW_SetWidgetHidden(sb->vscroll, SDL_FALSE); + KW_SetWidgetHidden(sb->hscroll, SDL_TRUE); + KW_DisableWidgetHint(sb->vscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + KW_EnableWidgetHint(sb->hscroll, KW_WIDGETHINT_IGNOREINPUTEVENTS); + break; + }; +} diff --git a/src/KW_scrollbox.h b/src/KW_scrollbox.h index d9438ee..8899450 100644 --- a/src/KW_scrollbox.h +++ b/src/KW_scrollbox.h @@ -1,34 +1,50 @@ -#ifndef KW_SCROLLBOX_H -#define KW_SCROLLBOX_H - -#include "KW_gui.h" -#include "KW_widget.h" - -/** - * \brief Creates a frame that can scroll its children widgets. - * \details Unless specified otherwise, the scrollbox will scroll its children - * both horizonatlly and vertically, contained by its geometry. All - * childrens will be clipped to its geometry. - * - * The scroll box will manage the geometry of each children widget when - * its scrolled. - * \param geometry The geometry of this scrollbox. Contents will be clipped to - * its internal area (inside borders). - */ -extern DECLSPEC KW_Widget * KW_CreateScrollbox(KW_GUI * gui, KW_Widget * parent, const KW_Rect * geometry); - -/** - * \brief Scrolls vertically by a given amount in pixels. - * \param scrollbox The scrollbox widget to scroll its contents. - * \param amount The amount of pixels to vertically scroll. - */ -extern DECLSPEC void KW_ScrollboxVerticalScroll(KW_Widget * scrollbox, int amount); - -/** - * \brief Scrolls horizontally by a given amount in pixels. - * \param scrollbox The scrollbox widget to scroll its contents. - * \param amount The amount of pixels to vertically scroll. - */ -extern DECLSPEC void KW_ScrollboxHorizontalScroll(KW_Widget * scrollbox, int amount); - -#endif +#ifndef KW_SCROLLBOX_H +#define KW_SCROLLBOX_H + +#include "KW_gui.h" +#include "KW_widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum KW_ScrollboxType { + KW_SCROLLBOX_BOOTH, /** Allow both verical and horizontal scrolling (default). */ + KW_SCROLLBOX_VERTICAL, /** Allow only verticall scrolling */ + KW_SCROLLBOX_HORIZONTAL /** Allow only horizontal scrolling. */ +} KW_ScrollboxType; + +/** + * \brief Creates a frame that can scroll its children widgets. + * \details Unless specified otherwise, the scrollbox will scroll its children + * both horizonatlly and vertically, contained by its geometry. All + * childrens will be clipped to its geometry. + * + * The scroll box will manage the geometry of each children widget when + * its scrolled. + * \param geometry The geometry of this scrollbox. Contents will be clipped to + * its internal area (inside borders). + */ +extern DECLSPEC KW_Widget * KW_CreateScrollbox(KW_GUI * gui, KW_Widget * parent, const SDL_Rect * geometry); + +/** + * \brief Scrolls vertically by a given amount in pixels. + * \param scrollbox The scrollbox widget to scroll its contents. + * \param amount The amount of pixels to vertically scroll. + */ +extern DECLSPEC void KW_ScrollboxVerticalScroll(KW_Widget * scrollbox, int amount); + +/** + * \brief Scrolls horizontally by a given amount in pixels. + * \param scrollbox The scrollbox widget to scroll its contents. + * \param amount The amount of pixels to vertically scroll. + */ +extern DECLSPEC void KW_ScrollboxHorizontalScroll(KW_Widget * scrollbox, int amount); + +extern DECLSPEC void KW_ScrollboxSetType(KW_Widget * scrollbox, KW_ScrollboxType type); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_scrollbox_internal.c b/src/KW_scrollbox_internal.c index 5d27be9..c82dc3a 100644 --- a/src/KW_scrollbox_internal.c +++ b/src/KW_scrollbox_internal.c @@ -1,140 +1,140 @@ -#include "KW_scrollbox_internal.h" -#include "KW_widget.h" -#include "KW_scrollbox.h" -#include "KW_gui.h" -#include "KW_tilerenderer.h" - - -KW_Scrollbox * AllocScrollbox() { - KW_Scrollbox * scrollbox = calloc(sizeof(*scrollbox), 1); - return scrollbox; -} - -void RenderScrollboxFrame(KW_Scrollbox * sb) { - KW_Surface * tileset; - KW_Rect targetgeom; - KW_Widget * widget = sb->root; - tileset = KW_GetWidgetTilesetSurface(widget); - KW_GetWidgetGeometry(widget, &targetgeom); - - /* render bg frame */ - if (sb->framerender != NULL) SDL_DestroyTexture(sb->framerender); - sb->framerender = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 9, 0, targetgeom.w, targetgeom.h); -} - -void PaintScrollboxFrame(KW_Widget * widget) { - KW_Rect targetgeom, innergeom, outergeom, boxgeom; - KW_Rect scrollgeom; - float innerh, innerw; - KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); - - KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); - KW_GetWidgetGeometry(widget, &boxgeom); - KW_GetWidgetGeometry(sb->outer, &outergeom); - - /* check if inner rectancle changed size */ - KW_GetWidgetComposedGeometry(sb->inner, &innergeom); - if (sb->innercomposite.x != innergeom.x || - sb->innercomposite.y != innergeom.y || - sb->innercomposite.w != innergeom.w || - sb->innercomposite.h != innergeom.h) - { - /* vertical scroll stuff */ - innerh = innergeom.h; - KW_GetWidgetGeometry(sb->vscroll, &scrollgeom); - scrollgeom.x = boxgeom.w - TILESIZE * 3; - scrollgeom.w = TILESIZE *2; - scrollgeom.h = (outergeom.h / innerh) * outergeom.h; - scrollgeom.y = (-innergeom.y / innerh) * outergeom.h + TILESIZE; - innergeom.h = innerh; - KW_SetWidgetGeometry(sb->vscroll, &scrollgeom); - - /* horizontal scroll stuff */ - innerw = innergeom.w; - KW_GetWidgetGeometry(sb->hscroll, &scrollgeom); - scrollgeom.y = boxgeom.h - TILESIZE * 3; - scrollgeom.w = (outergeom.w / innerw) * outergeom.w; - scrollgeom.h = TILESIZE * 2; - scrollgeom.x = (-innergeom.x / innerw) * outergeom.w + TILESIZE; - innergeom.w = innerw; - KW_SetWidgetGeometry(sb->hscroll, &scrollgeom); - sb->innercomposite = innergeom; - } - - KW_ScrollboxVerticalScroll(sb->root, 0); - KW_ScrollboxHorizontalScroll(sb->root, 0); - - KW_RenderCopy(KW_GetWidgetRenderer(widget), sb->framerender, NULL, &targetgeom); -} - -void VerticalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel) { - KW_Widget * root = KW_GetWidgetParent(widget); - KW_Scrollbox * sb = KW_GetWidgetData(root, KW_WIDGETTYPE_SCROLLBOX); - KW_Rect outergeom; - KW_GetWidgetGeometry(sb->outer, &outergeom); - KW_ScrollboxVerticalScroll(sb->root, -yrel * (sb->innercomposite.h / outergeom.h * 1.0f)); -} - -void ChildrenChange(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * children) { - /* nothing else should be on the root */ - if (what == KW_CHILDRENCHANGE_ADDED) { - KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); - KW_ReparentWidget(children, sb->inner); - } -} - - -void RootScrollboxGeometryChange(KW_Widget * widget, const KW_Rect * geometry, const KW_Rect * oldgeom) { - KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); - KW_Rect rootgeom, areageom; - rootgeom = *geometry; - - /* configure outer geometry */ - areageom.w = rootgeom.w - TILESIZE * 4; - areageom.h = rootgeom.h - TILESIZE * 4; - areageom.x = TILESIZE; areageom.y = TILESIZE; - KW_SetWidgetGeometry(sb->outer, &areageom); - - /* configure inner geometry without changing x/y */ - KW_GetWidgetGeometry(sb->inner, &areageom); - areageom.w = rootgeom.w - TILESIZE * 4; - areageom.h = rootgeom.h - TILESIZE * 4; - KW_SetWidgetGeometry(sb->inner, &areageom); - sb->innercomposite.x = sb->innercomposite.y = sb->innercomposite.w = sb->innercomposite.h = 0; - - if (geometry->w != oldgeom->w || geometry->h != oldgeom->h) { - /* re-renders scrollbox frame */ - RenderScrollboxFrame(sb); - } -} - - -void HorizontalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel) { - KW_Widget * root = KW_GetWidgetParent(widget); - KW_Scrollbox * sb = KW_GetWidgetData(root, KW_WIDGETTYPE_SCROLLBOX); - KW_Rect outergeom; - KW_GetWidgetGeometry(sb->outer, &outergeom); - KW_ScrollboxHorizontalScroll(sb->root, -xrel * (sb->innercomposite.w / outergeom.w * 1.0f)); -} - - -void DestroyScrollboxFrame(KW_Widget * widget) { - -} - - -void ScrollboxKeyUp(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code) { - KW_Scrollbox * scrollbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); - if (scrollbox == NULL) - scrollbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_NONE); - switch (code) { - case SDL_SCANCODE_UP: - KW_ScrollboxVerticalScroll(scrollbox->root, -5); - break; - case SDL_SCANCODE_DOWN: - KW_ScrollboxVerticalScroll(scrollbox->root, 5); - break; - default: - break; - } -} +#include "KW_scrollbox_internal.h" +#include "KW_widget.h" +#include "KW_scrollbox.h" +#include "KW_gui.h" +#include "KW_tilerenderer.h" + + +KW_Scrollbox * AllocScrollbox() { + KW_Scrollbox * scrollbox = calloc(sizeof(*scrollbox), 1); + return scrollbox; +} + +void RenderScrollboxFrame(KW_Scrollbox * sb) { + SDL_Surface * tileset; + SDL_Rect targetgeom; + KW_Widget * widget = sb->root; + tileset = KW_GetWidgetTilesetSurface(widget); + KW_GetWidgetGeometry(widget, &targetgeom); + + /* render bg frame */ + if (sb->framerender != NULL) SDL_DestroyTexture(sb->framerender); + sb->framerender = KW_CreateTileFrameTexture(KW_GetWidgetRenderer(widget), tileset, 9, 0, targetgeom.w, targetgeom.h); +} + +void PaintScrollboxFrame(KW_Widget * widget) { + SDL_Rect targetgeom, innergeom, outergeom, boxgeom; + SDL_Rect scrollgeom; + float innerh, innerw; + KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); + + KW_GetWidgetAbsoluteGeometry(widget, &targetgeom); + KW_GetWidgetGeometry(widget, &boxgeom); + KW_GetWidgetGeometry(sb->outer, &outergeom); + + /* check if inner rectancle changed size */ + KW_GetWidgetComposedGeometry(sb->inner, &innergeom); + if (sb->innercomposite.x != innergeom.x || + sb->innercomposite.y != innergeom.y || + sb->innercomposite.w != innergeom.w || + sb->innercomposite.h != innergeom.h) + { + /* vertical scroll stuff */ + innerh = innergeom.h; + KW_GetWidgetGeometry(sb->vscroll, &scrollgeom); + scrollgeom.x = boxgeom.w - TILESIZE * 3; + scrollgeom.w = TILESIZE *2; + scrollgeom.h = (outergeom.h / innerh) * outergeom.h; + scrollgeom.y = (-innergeom.y / innerh) * outergeom.h + TILESIZE; + innergeom.h = innerh; + KW_SetWidgetGeometry(sb->vscroll, &scrollgeom); + + /* horizontal scroll stuff */ + innerw = innergeom.w; + KW_GetWidgetGeometry(sb->hscroll, &scrollgeom); + scrollgeom.y = boxgeom.h - TILESIZE * 3; + scrollgeom.w = (outergeom.w / innerw) * outergeom.w; + scrollgeom.h = TILESIZE * 2; + scrollgeom.x = (-innergeom.x / innerw) * outergeom.w + TILESIZE; + innergeom.w = innerw; + KW_SetWidgetGeometry(sb->hscroll, &scrollgeom); + sb->innercomposite = innergeom; + } + + KW_ScrollboxVerticalScroll(sb->root, 0); + KW_ScrollboxHorizontalScroll(sb->root, 0); + + SDL_RenderCopy(KW_GetWidgetRenderer(widget), sb->framerender, NULL, &targetgeom); +} + +void VerticalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel) { + KW_Widget * root = KW_GetWidgetParent(widget); + KW_Scrollbox * sb = KW_GetWidgetData(root, KW_WIDGETTYPE_SCROLLBOX); + SDL_Rect outergeom; + KW_GetWidgetGeometry(sb->outer, &outergeom); + KW_ScrollboxVerticalScroll(sb->root, -yrel * (sb->innercomposite.h / outergeom.h * 1.0f)); +} + +void ChildrenChange(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * children) { + /* nothing else should be on the root */ + if (what == KW_CHILDRENCHANGE_ADDED) { + KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); + KW_ReparentWidget(children, sb->inner); + } +} + + +void RootScrollboxGeometryChange(KW_Widget * widget, const SDL_Rect * geometry, const SDL_Rect * oldgeom) { + KW_Scrollbox * sb = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); + SDL_Rect rootgeom, areageom; + rootgeom = *geometry; + + /* configure outer geometry */ + areageom.w = rootgeom.w - TILESIZE * 4; + areageom.h = rootgeom.h - TILESIZE * 4; + areageom.x = TILESIZE; areageom.y = TILESIZE; + KW_SetWidgetGeometry(sb->outer, &areageom); + + /* configure inner geometry without changing x/y */ + KW_GetWidgetGeometry(sb->inner, &areageom); + areageom.w = rootgeom.w - TILESIZE * 4; + areageom.h = rootgeom.h - TILESIZE * 4; + KW_SetWidgetGeometry(sb->inner, &areageom); + sb->innercomposite.x = sb->innercomposite.y = sb->innercomposite.w = sb->innercomposite.h = 0; + + if (geometry->w != oldgeom->w || geometry->h != oldgeom->h) { + /* re-renders scrollbox frame */ + RenderScrollboxFrame(sb); + } +} + + +void HorizontalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel) { + KW_Widget * root = KW_GetWidgetParent(widget); + KW_Scrollbox * sb = KW_GetWidgetData(root, KW_WIDGETTYPE_SCROLLBOX); + SDL_Rect outergeom; + KW_GetWidgetGeometry(sb->outer, &outergeom); + KW_ScrollboxHorizontalScroll(sb->root, -xrel * (sb->innercomposite.w / outergeom.w * 1.0f)); +} + + +void DestroyScrollboxFrame(KW_Widget * widget) { + +} + + +void ScrollboxKeyUp(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code) { + KW_Scrollbox * scrollbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_SCROLLBOX); + if (scrollbox == NULL) + scrollbox = KW_GetWidgetData(widget, KW_WIDGETTYPE_NONE); + switch (code) { + case SDL_SCANCODE_UP: + KW_ScrollboxVerticalScroll(scrollbox->root, -5); + break; + case SDL_SCANCODE_DOWN: + KW_ScrollboxVerticalScroll(scrollbox->root, 5); + break; + default: + break; + } +} diff --git a/src/KW_scrollbox_internal.h b/src/KW_scrollbox_internal.h index 96759b6..321bede 100644 --- a/src/KW_scrollbox_internal.h +++ b/src/KW_scrollbox_internal.h @@ -1,28 +1,29 @@ -#ifndef KW_SCROLLBOX_INTERNAL_H -#define KW_SCROLLBOX_INTERNAL_H - -#include "KW_widget.h" - -typedef struct KW_Scrollbox { - KW_Widget * root; - KW_Widget * outer; - KW_Widget * inner; - KW_Rect innercomposite; - KW_Texture * framerender; - int x; - int y; - KW_Widget * vscroll; - KW_Widget * hscroll; -} KW_Scrollbox; - -KW_Scrollbox * AllocScrollbox(); -void PaintScrollboxFrame(KW_Widget * widget); -void DestroyScrollboxFrame(KW_Widget * widget); -void ScrollboxKeyUp(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); -void VerticalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel); -void HorizontalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel); -void ChildrenChange(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * children); -void RootScrollboxGeometryChange(KW_Widget * widget, const KW_Rect * newgeom, const KW_Rect * oldgeom); -void RenderScrollboxFrame(KW_Scrollbox * sb); - -#endif +#ifndef KW_SCROLLBOX_INTERNAL_H +#define KW_SCROLLBOX_INTERNAL_H + +#include "KW_widget.h" + +typedef struct KW_Scrollbox { + KW_Widget * root; + KW_Widget * outer; + KW_Widget * inner; + SDL_Rect innercomposite; + SDL_Texture * framerender; + int x; + int y; + KW_Widget * vscroll; + KW_Widget * hscroll; + int scrolltype; +} KW_Scrollbox; + +KW_Scrollbox * AllocScrollbox(); +void PaintScrollboxFrame(KW_Widget * widget); +void DestroyScrollboxFrame(KW_Widget * widget); +void ScrollboxKeyUp(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); +void VerticalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel); +void HorizontalBarDrag(KW_Widget * widget, int x, int y, int xrel, int yrel); +void ChildrenChange(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * children); +void RootScrollboxGeometryChange(KW_Widget * widget, const SDL_Rect * newgeom, const SDL_Rect * oldgeom); +void RenderScrollboxFrame(KW_Scrollbox * sb); + +#endif diff --git a/src/KW_textrenderer.c b/src/KW_textrenderer.c new file mode 100644 index 0000000..bc3eb91 --- /dev/null +++ b/src/KW_textrenderer.c @@ -0,0 +1,18 @@ +#include "KW_textrenderer.h" + + +SDL_Texture * KW_RenderTextLine(TTF_Font * font, SDL_Renderer * renderer, const char * text, SDL_Color color, int styleflags) { + int previousstyle; + SDL_Surface * textsurface; + SDL_Texture * ret; + if (font == NULL || text == NULL) + return NULL; + + previousstyle = TTF_GetFontStyle(font); + TTF_SetFontStyle(font, styleflags); + textsurface = TTF_RenderUTF8_Blended(font, text, color); + ret = SDL_CreateTextureFromSurface(renderer, textsurface); + SDL_FreeSurface(textsurface); + TTF_SetFontStyle(font, previousstyle); + return ret; +} diff --git a/src/KW_textrenderer.h b/src/KW_textrenderer.h new file mode 100644 index 0000000..1828568 --- /dev/null +++ b/src/KW_textrenderer.h @@ -0,0 +1,56 @@ +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_TEXTRENDERER_H +#define KW_TEXTREDNERER_H +#include "SDL_ttf.h" +#include "KW_macros.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file KW_textrenderer.h + * + * Helper functions for text rendering with SDL_ttf + */ + +/** + * \brief Renders a single line of text. + * \details Renders a new texture from text. + * \param font The TTF_Font to use in text rendering. + * \param renderer The renderer that will render the returned texture. + * \param text The text to render. + * \param color The color to render this text with. + * \param styleflags A list of TTF_STYLE_* style flags to pass. + * \return The resulting texture. + */ +extern DECLSPEC SDL_Texture * KW_RenderTextLine(TTF_Font * font, SDL_Renderer * renderer, const char * text, SDL_Color color, int styleflags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_tilerenderer.c b/src/KW_tilerenderer.c index fccd0e8..8e67afe 100644 --- a/src/KW_tilerenderer.c +++ b/src/KW_tilerenderer.c @@ -1,216 +1,216 @@ -#include "KW_tilerenderer.h" - -void KW_RenderTile(KW_RenderDriver * renderer, KW_Texture * tileset, int column, int line, int x, int y) { - KW_Rect clip; - KW_Rect target; - clip.x = column * TILESIZE; - clip.y = line * TILESIZE; - clip.w = TILESIZE; - clip.h = TILESIZE; - - target.x = x; - target.y = y; - target.w = TILESIZE; - target.h = TILESIZE; - - KW_RenderCopy(renderer, tileset, &clip, &target); -} - -void KW_BlitTile(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int column, int line, int x, int y) { - KW_Rect clip; - KW_Rect target; - clip.x = column * TILESIZE; - clip.y = line * TILESIZE; - clip.w = TILESIZE; - clip.h = TILESIZE; - - target.x = x; - target.y = y; - target.w = TILESIZE; - target.h = TILESIZE; - - KW_BlitSurface(renderer, tileset, &clip, dst, &target); -} - - -void KW_RenderTileFill(KW_RenderDriver * renderer, KW_Texture * tileset, int column, int line, int x, int y, int w, int h) { - - int i; - int j; - - KW_Rect clip; - KW_Rect target; - clip.x = column * TILESIZE; - clip.y = line * TILESIZE; - clip.w = TILESIZE; - clip.h = TILESIZE; - - target.x = x; - target.y = y; - target.w = TILESIZE; - target.h = TILESIZE; - - /* iterate by column */ - for (i = x; i < x + w;) { - - /* set the target column */ - target.x = i; - - /* reset clipping */ - clip.w = TILESIZE; - - /* clip the width of the tile if it does not fit */ - if (i + TILESIZE > x + w) { - clip.w = w % TILESIZE; - } - target.w = clip.w; - - /* iterate by lines in a column */ - for (j = y; j < y + h;) { - /* set target line */ - target.y = j; - - /* reset clipping */ - clip.h = TILESIZE; - - /* clip tile heigh if it does not fit */ - if (j + TILESIZE > y + h) { - clip.h = h % TILESIZE; - } - target.h = clip.h; - - /* finaly render it */ - KW_RenderCopy(renderer, tileset, &clip, &target); - - j += TILESIZE; - } - - i += TILESIZE; - } -} - -void KW_BlitTileFill(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int column, int line, int x, int y, int w, int h) { - int i; - int j; - - KW_Rect clip; - KW_Rect target; - clip.x = column * TILESIZE; - clip.y = line * TILESIZE; - clip.w = TILESIZE; - clip.h = TILESIZE; - - target.x = x; - target.y = y; - target.w = TILESIZE; - target.h = TILESIZE; - - /* iterate by column */ - for (i = x; i < x + w;) { - - /* set the target column */ - target.x = i; - - /* reset clipping */ - clip.w = TILESIZE; - - /* clip the width of the tile if it does not fit */ - if (i + TILESIZE > x + w) { - clip.w = w % TILESIZE; - } - target.w = clip.w; - - /* iterate by lines in a column */ - for (j = y; j < y + h;) { - /* set target line */ - target.y = j; - - /* reset clipping */ - clip.h = TILESIZE; - - /* clip tile heigh if it does not fit */ - if (j + TILESIZE > y + h) { - clip.h = h % TILESIZE; - } - target.h = clip.h; - - /* finaly render it */ - KW_BlitSurface(renderer, tileset, &clip, dst, &target); - - j += TILESIZE; - } - - i += TILESIZE; - } -} - - -void KW_RenderTileFrame(KW_RenderDriver * renderer, KW_Texture * tileset, int startcolumn, int startline, int x, int y, int w, int h) { - /* fill with background */ - KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 1, x + TILESIZE, y + TILESIZE, w - TILESIZE * 2, h - TILESIZE * 2); - - /* fill top */ - KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 0, x + TILESIZE, y, w - TILESIZE * 2, TILESIZE); - - /* fill bottom */ - KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 2, x + TILESIZE, y + h - TILESIZE, w - TILESIZE * 2, TILESIZE); - - /* fill left */ - KW_RenderTileFill(renderer, tileset, startcolumn + 0, startline + 1, x, y + TILESIZE, TILESIZE, h - TILESIZE * 2); - - /* fill right */ - KW_RenderTileFill(renderer, tileset, startcolumn + 2, startline + 1, x + (w - TILESIZE), y + TILESIZE, TILESIZE, h - TILESIZE * 2); - - /* render top left */ - KW_RenderTile(renderer, tileset, startcolumn + 0, startline + 0, x, y); - - /* render top right */ - KW_RenderTile(renderer, tileset, startcolumn + 2, startline + 0, x + w - TILESIZE, y); - - /* render bottom left */ - KW_RenderTile(renderer, tileset, startcolumn + 0, startline + 2, x, y + h - TILESIZE); - - /* render bottom right */ - KW_RenderTile(renderer, tileset, startcolumn + 2, startline + 2, x + (w - TILESIZE), y + h - TILESIZE); -} - -void KW_BlitTileFrame(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int startcolumn, int startline, int x, int y, int w, int h) { - /* fill with background */ - KW_BlitTileFill(renderer, dst, tileset, startcolumn + 1, startline + 1, x + TILESIZE, y + TILESIZE, w - TILESIZE * 2, h - TILESIZE * 2); - - /* fill top */ - KW_BlitTileFill(renderer, dst, tileset, startcolumn + 1, startline + 0, x + TILESIZE, y, w - TILESIZE * 2, TILESIZE); - - /* fill bottom */ - KW_BlitTileFill(renderer, dst, tileset, startcolumn + 1, startline + 2, x + TILESIZE, y + h - TILESIZE, w - TILESIZE * 2, TILESIZE); - - /* fill left */ - KW_BlitTileFill(renderer, dst, tileset, startcolumn + 0, startline + 1, x, y + TILESIZE, TILESIZE, h - TILESIZE * 2); - - /* fill right */ - KW_BlitTileFill(renderer, dst, tileset, startcolumn + 2, startline + 1, x + (w - TILESIZE), y + TILESIZE, TILESIZE, h - TILESIZE * 2); - - /* render top left */ - KW_BlitTile(renderer, dst, tileset, startcolumn + 0, startline + 0, x, y); - - /* render top right */ - KW_BlitTile(renderer, dst, tileset, startcolumn + 2, startline + 0, x + w - TILESIZE, y); - - /* render bottom left */ - KW_BlitTile(renderer, dst, tileset, startcolumn + 0, startline + 2, x, y + h - TILESIZE); - - /* render bottom right */ - KW_BlitTile(renderer, dst, tileset, startcolumn + 2, startline + 2, x + (w - TILESIZE), y + h - TILESIZE); -} - -KW_Texture * KW_CreateTileFrameTexture(KW_RenderDriver * renderer, KW_Surface * tileset, int startcolumn, int startline, int w, int h) { - KW_Surface * target; - KW_Texture * result; - target = KW_CreateSurface(renderer, w, h); - KW_BlitTileFrame(renderer, target, tileset, startcolumn, startline, 0, 0, w, h); - result = KW_CreateTexture(renderer, target); - /* TODO: proper error handling */ - KW_ReleaseSurface(renderer, target); - return result; -} - +#include "KW_tilerenderer.h" + +void KW_RenderTile(SDL_Renderer * renderer, SDL_Texture * tileset, int column, int line, int x, int y) { + SDL_Rect clip; + SDL_Rect target; + clip.x = column * TILESIZE; + clip.y = line * TILESIZE; + clip.w = TILESIZE; + clip.h = TILESIZE; + + target.x = x; + target.y = y; + target.w = TILESIZE; + target.h = TILESIZE; + + SDL_RenderCopy(renderer, tileset, &clip, &target); +} + +void KW_BlitTile(SDL_Surface * dst, SDL_Surface * tileset, int column, int line, int x, int y) { + SDL_Rect clip; + SDL_Rect target; + clip.x = column * TILESIZE; + clip.y = line * TILESIZE; + clip.w = TILESIZE; + clip.h = TILESIZE; + + target.x = x; + target.y = y; + target.w = TILESIZE; + target.h = TILESIZE; + + SDL_BlitSurface(tileset, &clip, dst, &target); +} + + +void KW_RenderTileFill(SDL_Renderer * renderer, SDL_Texture * tileset, int column, int line, int x, int y, int w, int h) { + + int i; + int j; + + SDL_Rect clip; + SDL_Rect target; + clip.x = column * TILESIZE; + clip.y = line * TILESIZE; + clip.w = TILESIZE; + clip.h = TILESIZE; + + target.x = x; + target.y = y; + target.w = TILESIZE; + target.h = TILESIZE; + + /* iterate by column */ + for (i = x; i < x + w;) { + + /* set the target column */ + target.x = i; + + /* reset clipping */ + clip.w = TILESIZE; + + /* clip the width of the tile if it does not fit */ + if (i + TILESIZE > x + w) { + clip.w = w % TILESIZE; + } + target.w = clip.w; + + /* iterate by lines in a column */ + for (j = y; j < y + h;) { + /* set target line */ + target.y = j; + + /* reset clipping */ + clip.h = TILESIZE; + + /* clip tile heigh if it does not fit */ + if (j + TILESIZE > y + h) { + clip.h = h % TILESIZE; + } + target.h = clip.h; + + /* finaly render it */ + SDL_RenderCopy(renderer, tileset, &clip, &target); + + j += TILESIZE; + } + + i += TILESIZE; + } +} + +void KW_BlitTileFill(SDL_Surface * dst, SDL_Surface * tileset, int column, int line, int x, int y, int w, int h) { + int i; + int j; + + SDL_Rect clip; + SDL_Rect target; + clip.x = column * TILESIZE; + clip.y = line * TILESIZE; + clip.w = TILESIZE; + clip.h = TILESIZE; + + target.x = x; + target.y = y; + target.w = TILESIZE; + target.h = TILESIZE; + + /* iterate by column */ + for (i = x; i < x + w;) { + + /* set the target column */ + target.x = i; + + /* reset clipping */ + clip.w = TILESIZE; + + /* clip the width of the tile if it does not fit */ + if (i + TILESIZE > x + w) { + clip.w = w % TILESIZE; + } + target.w = clip.w; + + /* iterate by lines in a column */ + for (j = y; j < y + h;) { + /* set target line */ + target.y = j; + + /* reset clipping */ + clip.h = TILESIZE; + + /* clip tile heigh if it does not fit */ + if (j + TILESIZE > y + h) { + clip.h = h % TILESIZE; + } + target.h = clip.h; + + /* finaly render it */ + SDL_BlitSurface(tileset, &clip, dst, &target); + + j += TILESIZE; + } + + i += TILESIZE; + } +} + + +void KW_RenderTileFrame(SDL_Renderer * renderer, SDL_Texture * tileset, int startcolumn, int startline, int x, int y, int w, int h) { + /* fill with background */ + KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 1, x + TILESIZE, y + TILESIZE, w - TILESIZE * 2, h - TILESIZE * 2); + + /* fill top */ + KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 0, x + TILESIZE, y, w - TILESIZE * 2, TILESIZE); + + /* fill bottom */ + KW_RenderTileFill(renderer, tileset, startcolumn + 1, startline + 2, x + TILESIZE, y + h - TILESIZE, w - TILESIZE * 2, TILESIZE); + + /* fill left */ + KW_RenderTileFill(renderer, tileset, startcolumn + 0, startline + 1, x, y + TILESIZE, TILESIZE, h - TILESIZE * 2); + + /* fill right */ + KW_RenderTileFill(renderer, tileset, startcolumn + 2, startline + 1, x + (w - TILESIZE), y + TILESIZE, TILESIZE, h - TILESIZE * 2); + + /* render top left */ + KW_RenderTile(renderer, tileset, startcolumn + 0, startline + 0, x, y); + + /* render top right */ + KW_RenderTile(renderer, tileset, startcolumn + 2, startline + 0, x + w - TILESIZE, y); + + /* render bottom left */ + KW_RenderTile(renderer, tileset, startcolumn + 0, startline + 2, x, y + h - TILESIZE); + + /* render bottom right */ + KW_RenderTile(renderer, tileset, startcolumn + 2, startline + 2, x + (w - TILESIZE), y + h - TILESIZE); +} + +void KW_BlitTileFrame(SDL_Surface * dst, SDL_Surface * tileset, int startcolumn, int startline, int x, int y, int w, int h) { + /* fill with background */ + KW_BlitTileFill(dst, tileset, startcolumn + 1, startline + 1, x + TILESIZE, y + TILESIZE, w - TILESIZE * 2, h - TILESIZE * 2); + + /* fill top */ + KW_BlitTileFill(dst, tileset, startcolumn + 1, startline + 0, x + TILESIZE, y, w - TILESIZE * 2, TILESIZE); + + /* fill bottom */ + KW_BlitTileFill(dst, tileset, startcolumn + 1, startline + 2, x + TILESIZE, y + h - TILESIZE, w - TILESIZE * 2, TILESIZE); + + /* fill left */ + KW_BlitTileFill(dst, tileset, startcolumn + 0, startline + 1, x, y + TILESIZE, TILESIZE, h - TILESIZE * 2); + + /* fill right */ + KW_BlitTileFill(dst, tileset, startcolumn + 2, startline + 1, x + (w - TILESIZE), y + TILESIZE, TILESIZE, h - TILESIZE * 2); + + /* render top left */ + KW_BlitTile(dst, tileset, startcolumn + 0, startline + 0, x, y); + + /* render top right */ + KW_BlitTile(dst, tileset, startcolumn + 2, startline + 0, x + w - TILESIZE, y); + + /* render bottom left */ + KW_BlitTile(dst, tileset, startcolumn + 0, startline + 2, x, y + h - TILESIZE); + + /* render bottom right */ + KW_BlitTile(dst, tileset, startcolumn + 2, startline + 2, x + (w - TILESIZE), y + h - TILESIZE); +} + +SDL_Texture * KW_CreateTileFrameTexture(SDL_Renderer * renderer, SDL_Surface * tileset, int startcolumn, int startline, int w, int h) { + SDL_Surface * target; + SDL_Texture * result; + target = SDL_CreateRGBSurface(0, w, h, 32, tileset->format->Rmask, tileset->format->Gmask, tileset->format->Bmask, tileset->format->Amask); + KW_BlitTileFrame(target, tileset, startcolumn, startline, 0, 0, w, h); + result = SDL_CreateTextureFromSurface(renderer, target); + /* TODO: proper error handling */ + SDL_FreeSurface(target); + return result; +} + diff --git a/src/KW_tilerenderer.h b/src/KW_tilerenderer.h index eca2817..13ba61d 100644 --- a/src/KW_tilerenderer.h +++ b/src/KW_tilerenderer.h @@ -1,180 +1,179 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_TILERENDERER_H -#define KW_TILERENDERER_H - -/** - * \file KW_tilerenderer.h - * - * Declare functions for rendering tiles from a tile set. - * The macro TILESIZE defines the size of the tile (w/h). - */ - -#include "KW_renderdriver.h" -#include "KW_macros.h" - -#define TILESIZE 8 - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Render a single tile from a tileset using the specified renderer. - * \param renderer The KW_RenderDriver that will render this tile. - * \param tileset The tileset texture to get this tile from. - * \param column The column in the tile set (starts at 0). - * \param line The line in the tile set (starts at 0). - * \param x The x coordinate in the screen to render the tile. - * \param y The y coordinate in the screen to render the tile. - */ -extern DECLSPEC void KW_RenderTile(KW_RenderDriver * renderer, KW_Texture * tileset, int column, int line, int x, int y); - -/** - * \brief Blit a single tile from a tileset to a surface. - * \param dst The destination KW_Surface. - * \param tileset The tileset surface to get this tile from. - * \param column The column in the tile set (starts at 0). - * \param line The line in the tile set (starts at 0). - * \param x The x coordinate in the destination surface to blit the tile. - * \param y The y coordinate in the destination surface to blit the tile. - */ -extern DECLSPEC void KW_BlitTile(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int column, int line, int x, int y); - -/** - * \brief Render a tile multiple times filling the whole w/h specified. - * \details The tile rendering will start at x/y and will fill until x+w/y+h, - * clipping when necessary. - * \param renderer The KW_RenderDriver that will render this tile. - * \param tileset The tileset texture to get this tile from. - * \param column The column in the tile set (starts at 0). - * \param line The line in the tile set (starts at 0). - * \param x The x coordinate in the screen to render the tile. - * \param y The y coordinate in the screen to render the tile. - * \param w The width to fill. - * \param h The height to fill. - */ -extern DECLSPEC void KW_RenderTileFill(KW_RenderDriver * renderer, KW_Texture * tileset, int column, int line, int x, int y, int w, int h); - -/** - * \brief Blit (copy) a tile multiple times filling the whole w/h specified. - * \details The tile rendering will start at x/y and will fill until x+w/y+h, - * clipping when necessary. - * \param dst Destination surface for this tile. - * \param tileset The tileset surface to get this tile from. - * \param column The column in the tile set (starts at 0). - * \param line The line in the tile set (starts at 0). - * \param x The x coordinate in the surface to blit the tile. - * \param y The y coordinate in the surface to blit the tile. - * \param w The width to fill. - * \param h The height to fill. - */ -extern DECLSPEC void KW_BlitTileFill(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int column, int line, int x, int y, int w, int h); - -/** - * \brief Render a frame using the set of tiles specified at startcolumn and startline. - * \details This function will make use of the 3x3 set of tiles to draw a frame. They are addressed by column-then-line, like this: - * - 0,0 is the top-left corner - * - 1,0 is the top - * - 2,0 is the top-right corner - * - * - 0,1 is the left - * - 1,1 is the middle - * - 2,1 is the right - * - * - 0,2 is the bottom-left corner - * - 1,2 is the bottom - * - 2,2 is the bottom-right corner - * - * They are read column first, line second. - * - * .---------.---------.---------. - * | | | | - * | 0,0 | 1,0 | 2,0 | - * | | | | - * .---------.---------.---------. - * | | | | - * | 0,1 | 1,1 | 2,1 | - * | | | | - * .---------.---------.---------. - * | | | | - * | 0,2 | 1,2 | 2,2 | - * | | | | - * `---------`---------`---------´ - * - * - * \param renderer The KW_RenderDriver that will render this frame. - * \param tileset The tileset texture to get this frame set from. - * \param startcolumn The column in the tile set (starts at 0). - * \param startline The line in the tile set (starts at 0). - * \param x The x coordinate in the screen to render the tiles. - * \param y The y coordinate in the screen to render the tiles. - * \param w The width to fill. - * \param h The height to fill. - */ -extern DECLSPEC void KW_RenderTileFrame(KW_RenderDriver * renderer, KW_Texture * tileset, int startcolumn, int startline, int x, int y, int w, int h); - -/** - * \brief Blit a frame from tileset into a surface. - * \details The arguments of this function are equivalent to KW_RenderTileFrame, - * except that instead of KW_Texture, it uses a KW_Surface for the - * tileset. Useful for caching and pixel manipulations before - * having a texture. - * \param dst The destination surface. Must be created preferably using the - * same format as the tileset surface. (tilesest->format field). - * \param tileset The source tileset surface. - * \param startcolumn The column in the tile set (starts at 0). - * \param startline The line in the tile set (starts at 0). - * \param x The x coordinate in the screen to render the tiles. - * \param y The y coordinate in the screen to render the tiles. - * \param w The width to fill. - * \param h The height to fill. - */ -extern DECLSPEC void KW_BlitTileFrame(KW_RenderDriver * renderer, KW_Surface * dst, KW_Surface * tileset, int startcolumn, int startline, int x, int y, int w, int h); - -/** - * \brief Creates a KW_Texture from a frame to be used as cache. - * \details Use this function to create a single KW_Texture made of - * tiles from the tileset (as in KW_BlitFrame or KW_RenderTileFrame) to - * be rendered later as a whole instead of rendering each tile - * separately (which is very slow for big frames). - * - * Keep in mind that calling this function every frame is *much* slower - * than render each tile of a frame directly. This function is for - * widgets that are very big and/or don't change very often. - * \param renderer The KW_RenderDriver that will render this frame. - * \param tileset The tileset surface to get this frame set from. - * \param startcolumn The column in the tile set (starts at 0). - * \param startline The line in the tile set (starts at 0). - * \param w The width to fill. - * \param h The height to fill. - */ -extern DECLSPEC KW_Texture * KW_CreateTileFrameTexture(KW_RenderDriver * renderer, KW_Texture * tileset, int startcolumn, int startline, int w, int h); - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_TILERENDERER_H +#define KW_TILERENDERER_H + +/** + * \file KW_tilerenderer.h + * + * Declare functions for rendering tiles from a tile set. + * The macro TILESIZE defines the size of the tile (w/h). + */ + +#include "SDL.h" +#include "KW_macros.h" +#define TILESIZE 8 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Render a single tile from a tileset using the specified renderer. + * \param renderer The SDL_Renderer that will render this tile. + * \param tileset The tileset texture to get this tile from. + * \param column The column in the tile set (starts at 0). + * \param line The line in the tile set (starts at 0). + * \param x The x coordinate in the screen to render the tile. + * \param y The y coordinate in the screen to render the tile. + */ +extern DECLSPEC void KW_RenderTile(SDL_Renderer * renderer, SDL_Texture * tileset, int column, int line, int x, int y); + +/** + * \brief Blit a single tile from a tileset to a surface. + * \param dst The destination SDL_Surface. + * \param tileset The tileset surface to get this tile from. + * \param column The column in the tile set (starts at 0). + * \param line The line in the tile set (starts at 0). + * \param x The x coordinate in the destination surface to blit the tile. + * \param y The y coordinate in the destination surface to blit the tile. + */ +extern DECLSPEC void KW_BlitTile(SDL_Surface * dst, SDL_Surface * tileset, int column, int line, int x, int y); + +/** + * \brief Render a tile multiple times filling the whole w/h specified. + * \details The tile rendering will start at x/y and will fill until x+w/y+h, + * clipping when necessary. + * \param renderer The SDL_Renderer that will render this tile. + * \param tileset The tileset texture to get this tile from. + * \param column The column in the tile set (starts at 0). + * \param line The line in the tile set (starts at 0). + * \param x The x coordinate in the screen to render the tile. + * \param y The y coordinate in the screen to render the tile. + * \param w The width to fill. + * \param h The height to fill. + */ +extern DECLSPEC void KW_RenderTileFill(SDL_Renderer * renderer, SDL_Texture * tileset, int column, int line, int x, int y, int w, int h); + +/** + * \brief Blit (copy) a tile multiple times filling the whole w/h specified. + * \details The tile rendering will start at x/y and will fill until x+w/y+h, + * clipping when necessary. + * \param dst Destination surface for this tile. + * \param tileset The tileset surface to get this tile from. + * \param column The column in the tile set (starts at 0). + * \param line The line in the tile set (starts at 0). + * \param x The x coordinate in the surface to blit the tile. + * \param y The y coordinate in the surface to blit the tile. + * \param w The width to fill. + * \param h The height to fill. + */ +extern DECLSPEC void KW_BlitTileFill(SDL_Surface * dst, SDL_Surface * tileset, int column, int line, int x, int y, int w, int h); + +/** + * \brief Render a frame using the set of tiles specified at startcolumn and startline. + * \details This function will make use of the 3x3 set of tiles to draw a frame. They are addressed by column-then-line, like this: + * - 0,0 is the top-left corner + * - 1,0 is the top + * - 2,0 is the top-right corner + * + * - 0,1 is the left + * - 1,1 is the middle + * - 2,1 is the right + * + * - 0,2 is the bottom-left corner + * - 1,2 is the bottom + * - 2,2 is the bottom-right corner + * + * They are read column first, line second. + * + * .---------.---------.---------. + * | | | | + * | 0,0 | 1,0 | 2,0 | + * | | | | + * .---------.---------.---------. + * | | | | + * | 0,1 | 1,1 | 2,1 | + * | | | | + * .---------.---------.---------. + * | | | | + * | 0,2 | 1,2 | 2,2 | + * | | | | + * `---------`---------`---------´ + * + * + * \param renderer The SDL_Renderer that will render this frame. + * \param tileset The tileset texture to get this frame set from. + * \param startcolumn The column in the tile set (starts at 0). + * \param startline The line in the tile set (starts at 0). + * \param x The x coordinate in the screen to render the tiles. + * \param y The y coordinate in the screen to render the tiles. + * \param w The width to fill. + * \param h The height to fill. + */ +extern DECLSPEC void KW_RenderTileFrame(SDL_Renderer * renderer, SDL_Texture * tileset, int startcolumn, int startline, int x, int y, int w, int h); + +/** + * \brief Blit a frame from tileset into a surface. + * \details The arguments of this function are equivalent to KW_RenderTileFrame, + * except that instead of SDL_Texture, it uses a SDL_Surface for the + * tileset. Useful for caching and pixel manipulations before + * having a texture. + * \param dst The destination surface. Must be created preferably using the + * same format as the tileset surface. (tilesest->format field). + * \param tileset The source tileset surface. + * \param startcolumn The column in the tile set (starts at 0). + * \param startline The line in the tile set (starts at 0). + * \param x The x coordinate in the screen to render the tiles. + * \param y The y coordinate in the screen to render the tiles. + * \param w The width to fill. + * \param h The height to fill. + */ +extern DECLSPEC void KW_BlitTileFrame(SDL_Surface * dst, SDL_Surface * tileset, int startcolumn, int startline, int x, int y, int w, int h); + +/** + * \brief Creates a SDL_Texture from a frame to be used as cache. + * \details Use this function to create a single SDL_Texture made of + * tiles from the tileset (as in KW_BlitFrame or KW_RenderTileFrame) to + * be rendered later as a whole instead of rendering each tile + * separately (which is very slow for big frames). + * + * Keep in mind that calling this function every frame is *much* slower + * than render each tile of a frame directly. This function is for + * widgets that are very big and/or don't change very often. + * \param renderer The SDL_Renderer that will render this frame. + * \param tileset The tileset surface to get this frame set from. + * \param startcolumn The column in the tile set (starts at 0). + * \param startline The line in the tile set (starts at 0). + * \param w The width to fill. + * \param h The height to fill. + */ +extern DECLSPEC SDL_Texture * KW_CreateTileFrameTexture(SDL_Renderer * renderer, SDL_Surface * tileset, int startcolumn, int startline, int w, int h); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_widget.c b/src/KW_widget.c index cc31a1b..8377633 100644 --- a/src/KW_widget.c +++ b/src/KW_widget.c @@ -1,517 +1,574 @@ -#include "KW_widget_internal.h" -#include "KW_gui_internal.h" -#include "KW_widget.h" -#include - -KW_Widget * AllocWidget() { - KW_Widget * widget = calloc(1, sizeof(KW_Widget)); - return widget; -} - - -KW_Widget * KW_CreateWidget(KW_GUI * gui, KW_Widget * parent, KW_WidgetType type, const KW_Rect * geometry, KW_WidgetPaintFunction widgetpaint, KW_WidgetDestroyFunction widgetdestroy, void * priv) { - KW_Widget * widget = AllocWidget(); - widget->gui = gui; - widget->paint = widgetpaint; - widget->destroy = widgetdestroy; - widget->type = type; - /* set initial area as geometry */ - widget->composed = *geometry; - KW_ReparentWidget(widget, parent); - KW_SetWidgetGeometry(widget, geometry); - KW_UnblockWidgetInputEvents(widget); - widget->privdata = priv; - widget->tilesettexture = NULL; - widget->tilesetsurface = NULL; - return widget; -} - -KW_Widget * KW_GetWidgetParent(const KW_Widget * widget) { - return widget->parent == widget->gui->rootwidget ? NULL : widget->parent; -} - -KW_Widget * const * KW_GetWidgetChildren(const KW_Widget * widget, unsigned int * count) { - *count = widget->childrencount; - return widget->children; -} - - -void KW_SetWidgetTilesetSurface(KW_Widget * widget, KW_Surface * tileset) { - widget->tilesetsurface = tileset; - widget->tilesettexture = KW_CreateTexture(KW_GetWidgetRenderer(widget), tileset); -} - -KW_Texture * KW_GetWidgetTilesetTexture(KW_Widget * widget) { - return widget->tilesettexture == NULL ? widget->gui->tilesettexture : widget->tilesettexture; -} - -KW_Surface * KW_GetWidgetTilesetSurface(KW_Widget * widget) { - return widget->tilesetsurface == NULL ? widget->gui->tilesetsurface : widget->tilesetsurface; -} - -void * KW_GetWidgetData(const KW_Widget * widget, KW_WidgetType type) { - if (widget->type != type) return NULL; - return widget->privdata; -} - -KW_RenderDriver * KW_GetWidgetRenderer(const KW_Widget * widget) { - return KW_GetRenderer(KW_GetGUI(widget)); -} - -void KW_GetWidgetAbsoluteGeometry(const KW_Widget * widget, KW_Rect * geometry) { - *geometry = widget->absolute; -} - -void KW_SetWidgetData(KW_Widget * widget, void * data) { - widget->privdata = data; -} - -void KW_BlockWidgetInputEvents(KW_Widget * widget) { - KW_EnableWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS);; -} - -void KW_UnblockWidgetInputEvents(KW_Widget * widget) { - KW_DisableWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS); -} - -KW_bool KW_IsWidgetInputEventsBlocked(KW_Widget * widget) { - return KW_QueryWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS); -} - -void KW_DisableWidgetHint(KW_Widget * widget, KW_WidgetHint hint) { - widget->hints &= ~hint; -} - -void KW_EnableWidgetHint(KW_Widget * widget, KW_WidgetHint hint) { - widget->hints |= hint; -} - -KW_bool KW_QueryWidgetHint(const KW_Widget * widget, KW_WidgetHint hint) { - return ((widget->hints & hint) ? KW_TRUE : KW_FALSE); -} - - - - -void Reparent(KW_Widget * widget, KW_Widget * newparent); - -void FreeWidget(KW_Widget * widget, int freechildren) { - KW_Widget * tofree; - - /* recursively delete children */ - if (freechildren) { - while (widget->childrencount > 0) { - tofree = widget->children[0]; - Reparent(tofree, NULL); - FreeWidget(tofree, freechildren); - } - } - - free(widget->children); - if (widget->destroy != NULL) { - widget->destroy(widget); - } - free(widget); -} - -void KW_SetClipChildrenWidgets(KW_Widget * widget, KW_bool shouldclip) { - widget->clipchildren = shouldclip; -} - -/* recursively calculate absolute geometry */ -void CalculateAbsoluteGeometry(KW_Widget * widget) { - int i = 0; - KW_Rect oldabs = widget->absolute, parentabs; - KW_GetWidgetAbsoluteGeometry(widget->parent, &parentabs); /* get parent absolute */ - widget->absolute.x = widget->geometry.x + parentabs.x; - widget->absolute.y = widget->geometry.y + parentabs.y; - widget->absolute.w = widget->geometry.w; - widget->absolute.h = widget->geometry.h; - - /* absolute changed, children absolute must also change */ - if (oldabs.x != widget->absolute.x || oldabs.y != widget->absolute.y) { - for (i = 0; i < widget->childrencount; i++) { - CalculateAbsoluteGeometry(widget->children[i]); - } - } -} - -/* recursively calculate (childs->parent->parent->...->root) all composed geometries. - * - * They are relative to its parent, thus, if a child has a .x coordinate less than - * 0, it is outside the current widget box and it must be recalculated. The current - * widget parent must also be notified of this change if we happend to be outside parent box */ -void CalculateComposedGeometry(KW_Widget * widget) { - - KW_Rect composed, edges; - KW_Widget * children = NULL; - int i = 0; - if (widget->parent == NULL) return; - if (widget->clipchildren) { - widget->composed = widget->geometry; - return; - } - - edges = widget->geometry; - for (i = 0; i < widget->childrencount; i++) { - children = widget->children[i]; - KW_GetWidgetComposedGeometry(children, &composed); - if (composed.x + composed.w > edges.w) edges.w = composed.x + composed.w; - if (composed.y + composed.h > edges.h) edges.h = composed.y + composed.h; - if (composed.x < 0) edges.x += composed.x; - if (composed.y < 0) edges.y += composed.y; - } - if (edges.x < widget->geometry.x) edges.w += widget->geometry.x - edges.x; - if (edges.y < widget->geometry.y) edges.h += widget->geometry.y - edges.y; - - widget->composed = edges; - /* see if our composite geometry change is relevant to parent */ - if (widget->parent == NULL) return; - KW_GetWidgetComposedGeometry(widget->parent, &composed); - if (((widget->composed.x < composed.x) - || (widget->composed.y < composed.y) - || (widget->composed.w + widget->composed.x != composed.w) - || (widget->composed.h + widget->composed.y != composed.h) - ) - || - (widget->parent->parent == NULL) /* always calculate root geometry */ - ) - { - CalculateComposedGeometry(widget->parent); - } - /* TODO: callback for changed? */ -} - -void KW_GetWidgetComposedGeometry(const KW_Widget * widget, KW_Rect * composed) { - *composed = widget->composed; -} - -void KW_SetFocusedWidget(KW_Widget * widget) -{ - int count = 0, i = 0; - KW_OnFocusGain * gainhandlers = NULL; - KW_OnFocusLose * losehandlers = NULL; - KW_GUI * gui = NULL; - - if (widget == NULL || widget->gui == NULL) { - return; - } - gui = KW_GetWidgetGUI(widget); - if (widget != gui->currentfocus) { - /* warn that its losing focus */ - if (gui->currentfocus != NULL) { - count = gui->currentfocus->eventhandlers[KW_ON_FOCUSLOSE].count; - losehandlers = (KW_OnFocusLose *) gui->currentfocus->eventhandlers[KW_ON_FOCUSLOSE].handlers; - for (i = 0; i < count; i++) { - losehandlers[i](gui->currentfocus); - } - } - - /* watn that its gaining focus */ - count = widget->eventhandlers[KW_ON_FOCUSGAIN].count; - gainhandlers = (KW_OnFocusGain *) widget->eventhandlers[KW_ON_FOCUSGAIN].handlers; - for (i = 0; i < count; i++) { - gainhandlers[i](widget); - } - gui->currentfocus = widget; - } -} - -void KW_BringToFront(KW_Widget * widget) -{ - int i = 0, j = -1; - KW_Widget * wp = NULL; - if (widget == NULL || widget->parent == NULL || widget->parent->childrencount == 0) { - return; - } - wp = widget->parent; - if (wp->children[wp->childrencount - 1] == widget) { - /* already in front */ - return; - } - - /* iterate to find the position of widget */ - for (i = 0; i < wp->childrencount; i++) { - if (wp->children[i] == widget) { - j = i; - } - - /* move everything in front of it */ - if (j >= 0 && i + 1 < wp->childrencount) { - wp->children[i] = wp->children[i+1]; - } - } - - /* put widget at the last index */ - wp->children[wp->childrencount - 1] = widget; -} - -/* reparent version that allow us to parent to NULL */ -void Reparent(KW_Widget * widget, KW_Widget * newparent) { - int i = 0, j = -1; -#if !defined(NDEBUG) && defined(DEBUG_GEOMETRY_CHANGE) - printf("Reparenting %p: %d from %p to %p\n", (void*) widget, widget->type, (void*) widget->parent, (void*) newparent); -#endif - /* gotta remove from previous parent */ - - if (widget->parent != NULL) { - KW_Widget * wp = widget->parent; - - /* iterate to find the position of widget */ - for (i = 0; i < wp->childrencount; i++) { - if (wp->children[i] == widget) { - j = i; - } - - /* move everything in front of it */ - if (j >= 0 && i + 1 < wp->childrencount) { - wp->children[i] = wp->children[i+1]; - } - } - - /* realloc children array */ - wp->childrencount--; - if (wp->childrencount <= 0) { - free(wp->children); - wp->children = NULL; - } - else - wp->children = realloc(wp->children, wp->childrencount * sizeof(KW_Widget *)); - - /* warn parent widget handlers that children changed */ - for (i = 0; i < wp->eventhandlers[KW_ON_CHILDRENCHANGE].count; i++) { - KW_OnWidgetChildrenChange handler = (KW_OnWidgetChildrenChange) - wp->eventhandlers[KW_ON_CHILDRENCHANGE].handlers[i]; - handler(wp, KW_CHILDRENCHANGE_REMOVED, widget); - } - - /* need to recalculate old parent area */ - CalculateComposedGeometry(widget); - CalculateAbsoluteGeometry(widget); - } - - if (newparent != NULL) { - newparent->childrencount++; - newparent->children = realloc(newparent->children, newparent->childrencount * sizeof(KW_Widget *)); - newparent->children[newparent->childrencount-1] = widget; - widget->parent = newparent; - - /* warn new parent widget handlers that children array changed */ - for (i = 0; i < newparent->eventhandlers[KW_ON_CHILDRENCHANGE].count; i++) { - KW_OnWidgetChildrenChange handler = (KW_OnWidgetChildrenChange) - newparent->eventhandlers[KW_ON_CHILDRENCHANGE].handlers[i]; - handler(newparent, KW_CHILDRENCHANGE_ADDED, widget); - } - - /* need to recalculate new parent area */ - CalculateComposedGeometry(newparent); - } -} - - -/* public reparent that forces parenting to the root */ -void KW_ReparentWidget(KW_Widget * widget, KW_Widget * newparent) { - - /* don't allow a null parent. not for users, at least. */ - if (newparent == NULL) - newparent = widget->gui->rootwidget; - - /* don't allow widgets from different guis to interact */ - if (newparent->gui != widget->gui) - return; - - if (newparent == widget->parent) - return; - - Reparent(widget, newparent); -} - -void KW_DestroyWidget(KW_Widget * widget, int freechildren) { - /* Reparent every child of widget to widget->parent */ - if (!freechildren) { - while (widget->childrencount > 0) { - KW_ReparentWidget(widget->children[0], widget->parent); - } - } - FreeWidget(widget, freechildren); -} - -void KW_SetWidgetUserData(KW_Widget * widget, void * userdata) { - widget->userdata = userdata; -} - -void * KW_GetWidgetUserData(const KW_Widget * widget) { - return widget->userdata; -} - - - -void KW_PaintWidget(KW_Widget * root) { - int i = 0; - KW_Rect cliprect; - KW_RenderDriver * renderer = KW_GetWidgetRenderer(root); - - /* paint the root, then paint its childrens */ - if (root->paint != NULL) { - root->paint(root); - } - - if (root->clipchildren) { - KW_GetClipRect(renderer, &(root->oldcliprect)); - cliprect = root->absolute; - KW_SetClipRect(renderer, &cliprect, KW_FALSE); - } - - for (i = 0; i < root->childrencount; i++) { - KW_PaintWidget(root->children[i]); - } - - /* restore cliprect */ - if (root->clipchildren) { - KW_SetClipRect(renderer, &(root->oldcliprect), KW_TRUE); - } -} - -void KW_SetWidgetGeometry(KW_Widget * widget, const KW_Rect * geometry) { - int i; - KW_Rect old; - KW_OnGeometryChange handler; - if ((widget->geometry.x != geometry->x || - widget->geometry.y != geometry->y || - widget->geometry.w != geometry->w || - widget->geometry.h != geometry->h) - || - (geometry->x == 0 && geometry->y == 0 && geometry->w == 0 && geometry->h == 0)) - { - old = widget->geometry; - widget->geometry = *geometry; - CalculateComposedGeometry(widget); - CalculateAbsoluteGeometry(widget); - for (i = 0; i < widget->eventhandlers[KW_ON_GEOMETRYCHANGED].count; i++) { - handler = (KW_OnGeometryChange) widget->eventhandlers[KW_ON_GEOMETRYCHANGED].handlers[i]; - handler(widget, geometry, &old); - } - } -} - -void KW_GetWidgetGeometry(const KW_Widget * widget, KW_Rect * geometry) { - *geometry = widget->geometry; -} - - -KW_GUI * KW_GetWidgetGUI(const KW_Widget * widget) { - return widget->gui; -} - - -void KW_AddWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler) { - AddWidgetHandler(widget, KW_ON_DRAG, (WidgetHandler) handler); -} - -void KW_RemoveWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler) { - RemoveWidgetHandler(widget, KW_ON_DRAG, (WidgetHandler) handler); -} - -void KW_AddWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler) { - AddWidgetHandler(widget, KW_ON_DRAGSTART, (WidgetHandler) handler); -} - -void KW_RemoveWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler) { - RemoveWidgetHandler(widget, KW_ON_DRAGSTART, (WidgetHandler) handler); -} - -void KW_AddWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler) { - AddWidgetHandler(widget, KW_ON_DRAGSTOP, (WidgetHandler) handler); -} - -void KW_RemoveWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler) { - RemoveWidgetHandler(widget, KW_ON_DRAGSTOP, (WidgetHandler) handler); -} - -void KW_AddWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler) { - AddWidgetHandler(widget, KW_ON_MOUSEOVER, (WidgetHandler) handler); -} - -void KW_RemoveWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler) { - RemoveWidgetHandler(widget, KW_ON_MOUSEOVER, (WidgetHandler) handler); -} - -void KW_AddWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler) { - AddWidgetHandler(widget, KW_ON_MOUSELEAVE, (WidgetHandler) handler); -} - -void KW_RemoveWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler) { - RemoveWidgetHandler(widget, KW_ON_MOUSELEAVE, (WidgetHandler) handler); -} - -void KW_AddWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler) { - AddWidgetHandler(widget, KW_ON_MOUSEDOWN, (WidgetHandler) handler); -} - -void KW_RemoveWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler) { - RemoveWidgetHandler(widget, KW_ON_MOUSEDOWN, (WidgetHandler) handler); -} - -void KW_AddWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseDown handler) { - AddWidgetHandler(widget, KW_ON_MOUSEUP, (WidgetHandler) handler); -} - -void KW_RemoveWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseDown handler) { - RemoveWidgetHandler(widget, KW_ON_MOUSEUP, (WidgetHandler) handler); -} - -void KW_AddWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler) { - AddWidgetHandler(widget, KW_ON_FOCUSGAIN, (WidgetHandler) handler); -} - -void KW_RemoveWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler) { - RemoveWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); -} - -void KW_AddWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler) { - AddWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); -} - -void KW_RemoveWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler) { - RemoveWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); -} - -void KW_AddWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler) { - AddWidgetHandler(widget, KW_ON_TEXTINPUT, (WidgetHandler) handler); -} - -void KW_RemoveWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler) { - RemoveWidgetHandler(widget, KW_ON_TEXTINPUT, (WidgetHandler) handler); -} - -void KW_AddWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler) { - AddWidgetHandler(widget, KW_ON_KEYDOWN, (WidgetHandler) handler); -} - -void KW_RemoveWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler) { - RemoveWidgetHandler(widget, KW_ON_KEYDOWN, (WidgetHandler) handler); -} - -void KW_AddWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler) { - AddWidgetHandler(widget, KW_ON_KEYUP, (WidgetHandler) handler); -} - -void KW_RemoveWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler) { - RemoveWidgetHandler(widget, KW_ON_KEYUP, (WidgetHandler) handler); -} - -void KW_AddWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler) { - AddWidgetHandler(widget, KW_ON_GEOMETRYCHANGED, (WidgetHandler) handler); -} - -void KW_RemoveWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler) { - RemoveWidgetHandler(widget, KW_ON_GEOMETRYCHANGED, (WidgetHandler) handler); -} - -void KW_AddWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler) { - AddWidgetHandler(widget, KW_ON_CHILDRENCHANGE, (WidgetHandler) handler); -} - -void KW_RemoveWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler) { - RemoveWidgetHandler(widget, KW_ON_CHILDRENCHANGE, (WidgetHandler) handler); -} +#include "KW_widget_internal.h" +#include "KW_gui_internal.h" +#include "KW_gui.h" +#include "KW_widget.h" +#include + +KW_Widget * AllocWidget() { + KW_Widget * widget = calloc(1, sizeof(KW_Widget)); + return widget; +} + + +KW_Widget * KW_CreateWidget(KW_GUI * gui, KW_Widget * parent, KW_WidgetType type, const SDL_Rect * geometry, KW_WidgetPaintFunction widgetpaint, KW_WidgetDestroyFunction widgetdestroy, void * priv) { + KW_Widget * widget = AllocWidget(); + widget->gui = gui; + widget->paint = widgetpaint; + widget->destroy = widgetdestroy; + widget->type = type; + /* set initial area as geometry */ + widget->composed = *geometry; + KW_ReparentWidget(widget, parent); + KW_SetWidgetGeometry(widget, geometry); + KW_UnblockWidgetInputEvents(widget); + widget->privdata = priv; + widget->tilesettexture = NULL; + widget->tilesetsurface = NULL; + return widget; +} + +KW_Widget * KW_GetWidgetParent(const KW_Widget * widget) { + return widget->parent == widget->gui->rootwidget ? NULL : widget->parent; +} + +KW_Widget * const * KW_GetWidgetChildren(const KW_Widget * widget, unsigned int * count) { + *count = widget->childrencount; + return widget->children; +} + + +void KW_SetWidgetTilesetSurface(KW_Widget * widget, SDL_Surface * tileset) { + widget->tilesetsurface = tileset; + widget->tilesettexture = SDL_CreateTextureFromSurface(KW_GetWidgetRenderer(widget), tileset); +} + +SDL_Texture * KW_GetWidgetTilesetTexture(KW_Widget * widget) { + return widget->tilesettexture == NULL ? widget->gui->tilesettexture : widget->tilesettexture; +} + +SDL_Surface * KW_GetWidgetTilesetSurface(KW_Widget * widget) { + return widget->tilesetsurface == NULL ? widget->gui->tilesetsurface : widget->tilesetsurface; +} + +void * KW_GetWidgetData(const KW_Widget * widget, KW_WidgetType type) { + if (widget->type != type) return NULL; + return widget->privdata; +} + +SDL_Renderer * KW_GetWidgetRenderer(const KW_Widget * widget) { + return KW_GetRenderer(KW_GetGUI(widget)); +} + +void KW_GetWidgetAbsoluteGeometry(const KW_Widget * widget, SDL_Rect * geometry) { + *geometry = widget->absolute; +} + +void KW_SetWidgetData(KW_Widget * widget, void * data) { + widget->privdata = data; +} + +void KW_BlockWidgetInputEvents(KW_Widget * widget) { + KW_EnableWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS);; +} + +void KW_UnblockWidgetInputEvents(KW_Widget * widget) { + KW_DisableWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS); +} + +SDL_bool KW_IsWidgetInputEventsBlocked(KW_Widget * widget) { + return KW_QueryWidgetHint(widget, KW_WIDGETHINT_BLOCKINPUTEVENTS); +} + +void KW_DisableWidgetHint(KW_Widget * widget, KW_WidgetHint hint) { + widget->hints &= ~hint; +} + +void KW_EnableWidgetHint(KW_Widget * widget, KW_WidgetHint hint) { + widget->hints |= hint; +} + +SDL_bool KW_QueryWidgetHint(const KW_Widget * widget, KW_WidgetHint hint) { + return ((widget->hints & hint) ? SDL_TRUE : SDL_FALSE); +} + + + + +void Reparent(KW_Widget * widget, KW_Widget * newparent); + +void FreeWidget(KW_Widget * widget, int freechildren) { + KW_GUI* gui = KW_GetWidgetGUI(widget); + KW_Widget * tofree; + + /* make sure destroyed widget is not referenced as currently focused */ + if (gui->currentfocus == widget) { + KW_SetFocusedWidget(NULL); + } + + /* recursively delete children */ + if (freechildren) { + while (widget->childrencount > 0) { + tofree = widget->children[0]; + Reparent(tofree, NULL); + FreeWidget(tofree, freechildren); + } + } + + free(widget->children); + if (widget->destroy != NULL) { + widget->destroy(widget); + } + free(widget); +} + +void KW_SetClipChildrenWidgets(KW_Widget * widget, SDL_bool shouldclip) { + widget->clipchildren = shouldclip; +} + +/* recursively calculate absolute geometry */ +void CalculateAbsoluteGeometry(KW_Widget * widget) { + int i = 0; + SDL_Rect oldabs = widget->absolute, parentabs; + KW_GetWidgetAbsoluteGeometry(widget->parent, &parentabs); /* get parent absolute */ + widget->absolute.x = widget->geometry.x + parentabs.x; + widget->absolute.y = widget->geometry.y + parentabs.y; + widget->absolute.w = widget->geometry.w; + widget->absolute.h = widget->geometry.h; + + /* absolute changed, children absolute must also change */ + if (oldabs.x != widget->absolute.x || oldabs.y != widget->absolute.y) { + for (i = 0; i < widget->childrencount; i++) { + CalculateAbsoluteGeometry(widget->children[i]); + } + } +} + +/* recursively calculate (childs->parent->parent->...->root) all composed geometries. + * + * They are relative to its parent, thus, if a child has a .x coordinate less than + * 0, it is outside the current widget box and it must be recalculated. The current + * widget parent must also be notified of this change if we happend to be outside parent box */ +void CalculateComposedGeometry(KW_Widget * widget) { + + SDL_Rect composed, edges; + KW_Widget * children = NULL; + int i = 0; + if (widget->parent == NULL) return; + if (widget->clipchildren) { + widget->composed = widget->geometry; + return; + } + + edges = widget->geometry; + for (i = 0; i < widget->childrencount; i++) { + children = widget->children[i]; + KW_GetWidgetComposedGeometry(children, &composed); + if (composed.x + composed.w > edges.w) edges.w = composed.x + composed.w; + if (composed.y + composed.h > edges.h) edges.h = composed.y + composed.h; + if (composed.x < 0) edges.x += composed.x; + if (composed.y < 0) edges.y += composed.y; + } + if (edges.x < widget->geometry.x) edges.w += widget->geometry.x - edges.x; + if (edges.y < widget->geometry.y) edges.h += widget->geometry.y - edges.y; + + widget->composed = edges; + /* see if our composite geometry change is relevant to parent */ + if (widget->parent == NULL) return; + KW_GetWidgetComposedGeometry(widget->parent, &composed); + if (((widget->composed.x < composed.x) + || (widget->composed.y < composed.y) + || (widget->composed.w + widget->composed.x != composed.w) + || (widget->composed.h + widget->composed.y != composed.h) + ) + || + (widget->parent->parent == NULL) /* always calculate root geometry */ + ) + { + CalculateComposedGeometry(widget->parent); + } + /* TODO: callback for changed? */ +} + +void KW_GetWidgetComposedGeometry(const KW_Widget * widget, SDL_Rect * composed) { + *composed = widget->composed; +} + +void KW_SetFocusedWidget(KW_Widget * widget) +{ + int count = 0, i = 0; + KW_OnFocusGain * gainhandlers = NULL; + KW_OnFocusLose * losehandlers = NULL; + KW_GUI * gui = NULL; + + if (widget == NULL || widget->gui == NULL) { + return; + } + gui = KW_GetWidgetGUI(widget); + if (widget != gui->currentfocus) { + /* warn that its losing focus */ + if (gui->currentfocus != NULL) { + count = gui->currentfocus->eventhandlers[KW_ON_FOCUSLOSE].count; + losehandlers = (KW_OnFocusLose *) gui->currentfocus->eventhandlers[KW_ON_FOCUSLOSE].handlers; + for (i = 0; i < count; i++) { + losehandlers[i](gui->currentfocus); + } + } + + /* watn that its gaining focus */ + count = widget->eventhandlers[KW_ON_FOCUSGAIN].count; + gainhandlers = (KW_OnFocusGain *) widget->eventhandlers[KW_ON_FOCUSGAIN].handlers; + for (i = 0; i < count; i++) { + gainhandlers[i](widget); + } + gui->currentfocus = widget; + } +} + +void KW_BringToFront(KW_Widget * widget) +{ + int i = 0, j = -1; + KW_Widget * wp = NULL; + if (widget == NULL || widget->parent == NULL || widget->parent->childrencount == 0) { + return; + } + wp = widget->parent; + if (wp->children[wp->childrencount - 1] == widget) { + /* already in front */ + return; + } + + /* iterate to find the position of widget */ + for (i = 0; i < wp->childrencount; i++) { + if (wp->children[i] == widget) { + j = i; + } + + /* move everything in front of it */ + if (j >= 0 && i + 1 < wp->childrencount) { + wp->children[i] = wp->children[i+1]; + } + } + + /* put widget at the last index */ + wp->children[wp->childrencount - 1] = widget; +} + +/* reparent version that allow us to parent to NULL */ +void Reparent(KW_Widget * widget, KW_Widget * newparent) { + int i = 0, j = -1; +#if !defined(NDEBUG) && defined(DEBUG_GEOMETRY_CHANGE) + printf("Reparenting %p: %d from %p to %p\n", (void*) widget, widget->type, (void*) widget->parent, (void*) newparent); +#endif + /* gotta remove from previous parent */ + + if (widget->parent != NULL) { + KW_Widget * wp = widget->parent; + + /* iterate to find the position of widget */ + for (i = 0; i < wp->childrencount; i++) { + if (wp->children[i] == widget) { + j = i; + } + + /* move everything in front of it */ + if (j >= 0 && i + 1 < wp->childrencount) { + wp->children[i] = wp->children[i+1]; + } + } + + /* realloc children array */ + wp->childrencount--; + if (wp->childrencount <= 0) { + free(wp->children); + wp->children = NULL; + } + else + wp->children = realloc(wp->children, wp->childrencount * sizeof(KW_Widget *)); + + /* warn parent widget handlers that children changed */ + for (i = 0; i < wp->eventhandlers[KW_ON_CHILDRENCHANGE].count; i++) { + KW_OnWidgetChildrenChange handler = (KW_OnWidgetChildrenChange) + wp->eventhandlers[KW_ON_CHILDRENCHANGE].handlers[i]; + handler(wp, KW_CHILDRENCHANGE_REMOVED, widget); + } + + /* need to recalculate old parent area */ + CalculateComposedGeometry(widget); + CalculateAbsoluteGeometry(widget); + } + + if (newparent != NULL) { + newparent->childrencount++; + newparent->children = realloc(newparent->children, newparent->childrencount * sizeof(KW_Widget *)); + newparent->children[newparent->childrencount-1] = widget; + widget->parent = newparent; + + /* warn new parent widget handlers that children array changed */ + for (i = 0; i < newparent->eventhandlers[KW_ON_CHILDRENCHANGE].count; i++) { + KW_OnWidgetChildrenChange handler = (KW_OnWidgetChildrenChange) + newparent->eventhandlers[KW_ON_CHILDRENCHANGE].handlers[i]; + handler(newparent, KW_CHILDRENCHANGE_ADDED, widget); + } + + /* need to recalculate new parent area */ + CalculateComposedGeometry(newparent); + } +} + + +/* public reparent that forces parenting to the root */ +void KW_ReparentWidget(KW_Widget * widget, KW_Widget * newparent) { + + /* don't allow a null parent. not for users, at least. */ + if (newparent == NULL) + newparent = widget->gui->rootwidget; + + /* don't allow widgets from different guis to interact */ + if (newparent->gui != widget->gui) + return; + + if (newparent == widget->parent) + return; + + Reparent(widget, newparent); +} + +void KW_DestroyWidget(KW_Widget * widget, int freechildren) { + KW_GUI* gui = KW_GetWidgetGUI(widget); + + /* block updates to gui while we're destroying some widget */ + SDL_LockMutex(gui->evqueuelock); + + KW_SetMouseOverWidget(gui, NULL); + + /* Reparent every child of widget to widget->parent */ + if (!freechildren) { + while (widget->childrencount > 0) { + KW_ReparentWidget(widget->children[0], widget->parent); + } + } + + /* tell parent to forget about this widget */ + Reparent(widget, NULL); + + FreeWidget(widget, freechildren); + SDL_UnlockMutex(gui->evqueuelock); +} + +void KW_SetWidgetUserData(KW_Widget * widget, void * userdata) { + widget->userdata = userdata; +} + +void * KW_GetWidgetUserData(const KW_Widget * widget) { + return widget->userdata; +} + +void KW_SetWidgetHidden(KW_Widget * widget, SDL_bool hidden) { + widget->hidden = hidden; +} + +void KW_PaintWidget(KW_Widget * root) { + int i = 0; + SDL_Renderer * renderer = KW_GetWidgetRenderer(root); + SDL_Rect cliprect, viewport; + static SDL_RendererInfo info; + static int isopengl = -1; + +#if !defined(NDEBUG) && defined(DEBUG_PRINT_GEOMETRY_RECTANGLE) + SDL_Rect geom = root->composed; + Uint8 r, g, b, a; + float maxrgb; + if (root->parent) { + geom.x += root->parent->absolute.x; + geom.y += root->parent->absolute.y; + } +#endif + + if (isopengl < 0) { + SDL_GetRendererInfo(renderer, &info); + isopengl = (strcmp(info.name, "opengl") >= 0) ? 1 : 0; + } + + /* paint the root, then paint its childrens */ + if (root->paint != NULL && !root->hidden) { + root->paint(root); + } + + if (root->clipchildren) { + SDL_RenderGetClipRect(renderer, &(root->oldcliprect)); + cliprect = root->absolute; + if (isopengl) { + /* fix for SDL buggy opengl scissor test. See SDL bug 2269. + * Not sure about other renderers. */ + SDL_RenderGetViewport(renderer, &viewport); + cliprect.x += viewport.x; cliprect.y -= viewport.y; + } + SDL_RenderSetClipRect(renderer, &cliprect); + } + +#if !defined(NDEBUG) && defined(DEBUG_PRINT_GEOMETRY_RECTANGLE) + SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); + maxrgb = (KW_GetGUI(root)->currentmouseover == root ? 255.0f : 100.0f); + SDL_SetRenderDrawColor(renderer, (geom.x / (viewport.w * 1.0f) + 1) * maxrgb, (geom.y / (viewport.h * 1.0f)) * maxrgb, (geom.w + geom.h * 1.0f) / (viewport.w + viewport.h * 1.0f) * maxrgb, 128); + SDL_RenderFillRect(renderer, &geom); + SDL_SetRenderDrawColor(renderer, r, g, b, a); +#endif + for (i = 0; i < root->childrencount; i++) { + KW_PaintWidget(root->children[i]); + } + + /* restore cliprect */ + if (root->clipchildren) { + /* for us, empty cliprect still means clip disable. + * See https://bugzilla.libsdl.org/show_bug.cgi?id=2504 */ + if (!SDL_RectEmpty(&(root->oldcliprect))) { + SDL_RenderSetClipRect(renderer, &(root->oldcliprect)); + } else { + SDL_RenderSetClipRect(renderer, NULL); + } + } +} + +void KW_SetWidgetGeometry(KW_Widget * widget, const SDL_Rect * geometry) { + int i; + SDL_Rect old; + KW_OnGeometryChange handler; + if ((widget->geometry.x != geometry->x || + widget->geometry.y != geometry->y || + widget->geometry.w != geometry->w || + widget->geometry.h != geometry->h) + || + (geometry->x == 0 && geometry->y == 0 && geometry->w == 0 && geometry->h == 0)) + { + old = widget->geometry; + widget->geometry = *geometry; + CalculateComposedGeometry(widget); + CalculateAbsoluteGeometry(widget); + for (i = 0; i < widget->eventhandlers[KW_ON_GEOMETRYCHANGED].count; i++) { + handler = (KW_OnGeometryChange) widget->eventhandlers[KW_ON_GEOMETRYCHANGED].handlers[i]; + handler(widget, geometry, &old); + } + } +} + +void KW_GetWidgetGeometry(const KW_Widget * widget, SDL_Rect * geometry) { + *geometry = widget->geometry; +} + + +KW_GUI * KW_GetWidgetGUI(const KW_Widget * widget) { + return widget->gui; +} + + +void KW_AddWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler) { + AddWidgetHandler(widget, KW_ON_DRAG, (WidgetHandler) handler); +} + +void KW_RemoveWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler) { + RemoveWidgetHandler(widget, KW_ON_DRAG, (WidgetHandler) handler); +} + +void KW_AddWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler) { + AddWidgetHandler(widget, KW_ON_DRAGSTART, (WidgetHandler) handler); +} + +void KW_RemoveWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler) { + RemoveWidgetHandler(widget, KW_ON_DRAGSTART, (WidgetHandler) handler); +} + +void KW_AddWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler) { + AddWidgetHandler(widget, KW_ON_DRAGSTOP, (WidgetHandler) handler); +} + +void KW_RemoveWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler) { + RemoveWidgetHandler(widget, KW_ON_DRAGSTOP, (WidgetHandler) handler); +} + +void KW_AddWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler) { + AddWidgetHandler(widget, KW_ON_MOUSEOVER, (WidgetHandler) handler); +} + +void KW_RemoveWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler) { + RemoveWidgetHandler(widget, KW_ON_MOUSEOVER, (WidgetHandler) handler); +} + +void KW_AddWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler) { + AddWidgetHandler(widget, KW_ON_MOUSELEAVE, (WidgetHandler) handler); +} + +void KW_RemoveWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler) { + RemoveWidgetHandler(widget, KW_ON_MOUSELEAVE, (WidgetHandler) handler); +} + +void KW_AddWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler) { + AddWidgetHandler(widget, KW_ON_MOUSEDOWN, (WidgetHandler) handler); +} + +void KW_RemoveWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler) { + RemoveWidgetHandler(widget, KW_ON_MOUSEDOWN, (WidgetHandler) handler); +} + +void KW_AddWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseDown handler) { + AddWidgetHandler(widget, KW_ON_MOUSEUP, (WidgetHandler) handler); +} + +void KW_RemoveWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseDown handler) { + RemoveWidgetHandler(widget, KW_ON_MOUSEUP, (WidgetHandler) handler); +} + +void KW_AddWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler) { + AddWidgetHandler(widget, KW_ON_FOCUSGAIN, (WidgetHandler) handler); +} + +void KW_RemoveWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler) { + RemoveWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); +} + +void KW_AddWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler) { + AddWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); +} + +void KW_RemoveWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler) { + RemoveWidgetHandler(widget, KW_ON_FOCUSLOSE, (WidgetHandler) handler); +} + +void KW_AddWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler) { + AddWidgetHandler(widget, KW_ON_TEXTINPUT, (WidgetHandler) handler); +} + +void KW_RemoveWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler) { + RemoveWidgetHandler(widget, KW_ON_TEXTINPUT, (WidgetHandler) handler); +} + +void KW_AddWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler) { + AddWidgetHandler(widget, KW_ON_KEYDOWN, (WidgetHandler) handler); +} + +void KW_RemoveWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler) { + RemoveWidgetHandler(widget, KW_ON_KEYDOWN, (WidgetHandler) handler); +} + +void KW_AddWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler) { + AddWidgetHandler(widget, KW_ON_KEYUP, (WidgetHandler) handler); +} + +void KW_RemoveWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler) { + RemoveWidgetHandler(widget, KW_ON_KEYUP, (WidgetHandler) handler); +} + +void KW_AddWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler) { + AddWidgetHandler(widget, KW_ON_GEOMETRYCHANGED, (WidgetHandler) handler); +} + +void KW_RemoveWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler) { + RemoveWidgetHandler(widget, KW_ON_GEOMETRYCHANGED, (WidgetHandler) handler); +} + +void KW_AddWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler) { + AddWidgetHandler(widget, KW_ON_CHILDRENCHANGE, (WidgetHandler) handler); +} + +void KW_RemoveWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler) { + RemoveWidgetHandler(widget, KW_ON_CHILDRENCHANGE, (WidgetHandler) handler); +} diff --git a/src/KW_widget.h b/src/KW_widget.h index 50e25fb..e3d8c42 100644 --- a/src/KW_widget.h +++ b/src/KW_widget.h @@ -1,673 +1,667 @@ -/* - Copyright (c) 2014, Leonardo Guilherme de Freitas - All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef KW_WIDGET_H -#define KW_WIDGET_H - -#include "KW_macros.h" -#include "KW_renderdriver.h" -#include "SDL.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef enum { - KW_FALSE = 0, - KW_TRUE = 1 -} KW_bool; - - -/** - * \brief The KW_Widget type represents a widget on the KW_GUI instance. - * \details Regardless of the widget type, they are all represented by this opaque type. - */ -struct KW_Widget; -typedef struct KW_Widget KW_Widget; - - -struct KW_GUI; -typedef struct KW_GUI KW_GUI; - -/* forward declarations of these */ -extern DECLSPEC KW_RenderDriver * KW_GetRenderer(KW_GUI * gui); -extern DECLSPEC KW_GUI * KW_GetGUI(const KW_Widget * widget); - - - -typedef void (*KW_WidgetPaintFunction)(KW_Widget * widget); -typedef void (*KW_WidgetDestroyFunction)(KW_Widget * widget); - -/* mouse callbacks */ -typedef void (*KW_OnMouseOver)(KW_Widget * widget); -typedef void (*KW_OnMouseLeave)(KW_Widget * widget); -typedef void (*KW_OnMouseDown)(KW_Widget * widget, int button); -typedef void (*KW_OnMouseUp)(KW_Widget * widget, int button); - -/* drag callbacks */ -typedef void (*KW_OnDragStart)(KW_Widget * widget, int x, int y); -typedef void (*KW_OnDragStop)(KW_Widget * widget, int x, int y); -typedef void (*KW_OnDrag)(KW_Widget * widget, int x, int y, int relx, int rely); - -/* focus callbacks */ -typedef void (*KW_OnFocusGain)(KW_Widget * widget); -typedef void (*KW_OnFocusLose)(KW_Widget * widget); - -/* text and keyboard callbacks */ -typedef void (*KW_OnTextInput)(KW_Widget * widget, const char * text); -typedef void (*KW_OnKeyDown)(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); -typedef void (*KW_OnKeyUp)(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); - -/* widget internal events */ -typedef void (*KW_OnGeometryChange)(KW_Widget * widget, const KW_Rect * newgeom, const KW_Rect * oldgeom); - -/** - * \brief The event type when the children array changes. - * \details Whenever the direct children number of an array changes, this - * enum is used to indicate if it was insertion or a removal. - */ -typedef enum KW_WidgetChildrenChangeEvent { - KW_CHILDRENCHANGE_ADDED, - KW_CHILDRENCHANGE_REMOVED -} KW_WidgetChildrenChangeEvent; - - -typedef void (*KW_OnWidgetChildrenChange)(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * child); - -/** - * \brief The KW_WidgetType enumeration represents available widget types. - * \details Every widget created must set a widget type even if its a custom widget. - */ -typedef enum KW_WidgetType { - KW_WIDGETTYPE_NONE, - KW_WIDGETTYPE_FRAME, - KW_WIDGETTYPE_LABEL, - KW_WIDGETTYPE_BUTTON, - KW_WIDGETTYPE_EDITBOX, - KW_WIDGETTYPE_SCROLLBOX, - KW_WIDGETTYPE_CUSTOM0 = 0x100000, - KW_WIDGETTYPE_CUSTOM1, - KW_WIDGETTYPE_CUSTOM2, - KW_WIDGETTYPE_CUSTOM3, - KW_WIDGETTYPE_CUSTOM4, - KW_WIDGETTYPE_CUSTOM5, - KW_WIDGETTYPE_CUSTOM6, - KW_WIDGETTYPE_CUSTOM7, - KW_WIDGETTYPE_CUSTOM8, - KW_WIDGETTYPE_CUSTOM9, - KW_WIDGETTYPE_CUSTOM10, - KW_WIDGETTYPE_CUSTOM11, - KW_WIDGETTYPE_CUSTOM12, - KW_WIDGETTYPE_CUSTOM13, - KW_WIDGETTYPE_CUSTOM14, - KW_WIDGETTYPE_CUSTOM15, - KW_WIDGETTYPE_CUSTOM16, - KW_WIDGETTYPE_CUSTOM17, - KW_WIDGETTYPE_CUSTOM18, - KW_WIDGETTYPE_CUSTOM19, - KW_WIDGETTYPE_CUSTOM20 -} KW_WidgetType; - -/** - * \brief Set of hints to control how this widget operates. - * \details These hints can be queried by the widget implementation to change - * its behaviour. They are also used to change KiWi's behaviour when - * propagating input events, etc. - */ -typedef enum KW_WidgetHint { - /** Allow widgets to stretch tiles */ - KW_WIDGETHINT_ALLOWTILESTRETCH = 1 << 0, - - /** Makes KiWi avoid reporting input events to this widget and its children - * widget */ - KW_WIDGETHINT_BLOCKINPUTEVENTS = 1 << 1, - - /** Makes KiWi avoid reporting input event to this widget but still passes to - * its children widgets */ - KW_WIDGETHINT_IGNOREINPUTEVENTS = 1 << 2, - - /** Hints widget implementations that, if possible, the user wants a - * frameless version of it */ - KW_WIDGETHINT_FRAMELESS = 1 << 3 -} KW_WidgetHint; - -/** - * \brief Creates a new custom widget instance. - * \details If you want to provide a new custom widget this is the function that you should call. - * All KW_Widget instances are built using this class, if you should need additional widget - * information you can use the data parameter. - * - * The widgetpaint function is called to paint the widget after the parent widget has been painted, never - * before, so you are garanteed to be rendering on top of it. - * - * Widget geometry is relative to its parent. Consider the following figure: - * - * \verbatim - * - * 10x10.---------------------------. - * | Root Widget | - * | | - * | | - * 10x30.------------. | - * | |Root's Child| | - * | | | | - * | | 40x20.---------------. | - * | | | Child's Child | | - * | | | | | - * | | | | | - * | | `---------------´80x40 - * | | | | - * | `------------´70x90 | - * | | - * `-----------------------------´150x150 - * - * Geometry is represented as XxY+WxH. - * - * \endverbatim - * - * The root widget starts at 10x10. The child widget starts at 10x30 *relative* to the root widget. That means that - * its absolute position is actually 20x40! The 'Child's Child' widget starts at 40x20 relative to its parent but its - * absolute position is (10 + 10 + 40, 10 + 30 + 20) = 60x60. If the parent widget moves, all its children move together. - * - * Widgets also have a composed geometry that is calculated by considering each child geometry. They represent the total - * area occupied by a widget and its children. In the above picture, - * the 'Root's Child' widget composed geometry is calculated by taking each of its children composed geometry and checking - * if they are out of the current widget composed geometry. Since 'Child's Child' width and height is out of 'Root's Child' - * geometry, 'Root's Child' composed geometry ends up not being 10x30+70x90, but rather 10x30+(40+80+70x90) = 10x30+120x90. - * Note the width was updated but not the height. - * - * The absolute geometry of a widget is calculating by iterating the parent tree and adding their position (x and y). - * - * \param gui The KW_GUI instace that will hold this widget in its widget tree. - * \param parent The parent widget. - * \param type The type of this widget. - * \param geometry The geometry of this widget *relative* to its parent. - * \param widgetpaing The paint function of this widget. - * \param widgetdestroy The destroy function of this widget. - * \param data Any private data associated with this widget. Mostly to be used by widget implementations. - * \returns The new widget. - */ -extern DECLSPEC KW_Widget * KW_CreateWidget(KW_GUI * gui, - KW_Widget * parent, - KW_WidgetType type, - const KW_Rect * geometry, - KW_WidgetPaintFunction widgetpaint, - KW_WidgetDestroyFunction widgetdestroy, - void * data); - - -/** - * \brief Change the parent of a widget to another parent. - * \details Remove \p widget as a child from its current parent and adds it as a child to \p parent. - * Every child of \p widget will then belong to the new \p parent tree. Note that \p widget - * geometry is **NOT** updated to keep it in the previous absolute position. You should call - * KW_SetWidgetGeometry() to update it. - * - * Keep in mind that this is one of the costliest functions to call in the KiWi library as it - * might involve memory reallocation both in the previous and in the new parent widget. The composed - * geometry also needs to be updated in both parents in a chain that might go as high as the root widget. - * You should avoid widget reparenting if you can. - * - * To make the widget a top-level widget you should pass \c NULL as the @p parent parameter. - * - * \param widget The widget that will have its parent changed. - * \param parent The new \p widget parent. - */ -extern DECLSPEC void KW_ReparentWidget(KW_Widget * widget, KW_Widget * parent); - -/** - * \brief Retrieves the parent widget of a widget. - * \param widget The KW_Widget instance to retrieve the parent from. - * \returns The parent widget or NULL if its a top-level widget. - */ -extern DECLSPEC KW_Widget * KW_GetWidgetParent(const KW_Widget * widget); - -/** - * \brief Returns an array of all childrens of this widget. - * \details The returned array is the same as stored internally and its contents - * can change if any reparenting is done after calling this function, - * thus, you should not store its value. -* \param widget The widget to return childrens from. - * \param[out] count If not NULL, the unsigned int pointed by it will have the - * children count of the widget. - * \returns An array of constant pointers to all childrens of \p widget. - */ -extern DECLSPEC KW_Widget * const * KW_GetWidgetChildren(const KW_Widget * widget, unsigned int * count); - -/** - * \brief Retrieves the current data associated with a widget. - * \details If you are implementing a custom widget, you must call this function to access the data you - * set up previously when the widget was created. - * \param widget The widget to retrieve the data from. - * \param type The widget type you're expecting @p widget to be - * \returns The data pointer or NULL if the widget types don't match. - */ -extern DECLSPEC void * KW_GetWidgetData(const KW_Widget * widget, KW_WidgetType type); - - -/** - * \brief Sets a pointer to user-specific data to be read later. - * \details Use this if you want to store user-specific state in this widget - * that could be shared among callbacks. Widget implementations should - * not use this. There's no check if it had any user data before, use - * with caution. - * \param widget The widget to set the user data. - * \param userdata The associated user data - */ -extern DECLSPEC void KW_SetWidgetUserData(KW_Widget * widget, void * userdata); - -/** - * \brief Returns the associated user data of a widget. - * \details Use this function to access a previously stored user data pointer. - * \param widget The widget to get userdata from. - * \returns The usertdata pointer - */ -extern DECLSPEC void * KW_GetWidgetUserData(const KW_Widget * widget); - -/** - * \brief Destroys a widget and free its resources. - * \details Any custom resource that you set (fonts, custom textures, etc) needs to be freed by you unless specified otherwise. - * \param widget The widget to destroy. - * \param destroychildren Set to 1 if you want also to destroy all childrens (and their childrens) of this widget. If not, they will be - * reparented to @p widget parent. - */ -extern DECLSPEC void KW_DestroyWidget(KW_Widget * widget, int destroychildren); - -/** - * \brief Returns the associated KW_GUI instance of a widget. - * \details If you have a widget instance, this is the means of retrieving its KW_GUI instance. - * \param widget The widget to get the KW_GUI instance from. - * \return The KW_GUI instance associated with the widget. - */ -extern DECLSPEC KW_GUI * KW_GetWidgetGUI(const KW_Widget * widget); - -/** - * \brief Returns the KW_RenderDriver associated with a KW_GUI instance that the @p widget is associated with. - * \details This is a helper function and its effects are the same of `KW_GetRenderer(KW_GetWidgetGUI(widget))` - * \param widget The widget to get the KW_RenderDriver instance from. - * \returns The associated KW_RenderDriver instance. - */ -extern DECLSPEC KW_RenderDriver * KW_GetWidgetRenderer(const KW_Widget * widget); - -/** - * \brief Sets a new geometry for a widget. - * \details Use this function if you need to change the widget relative position or its size. - * \param widget The widget that will have its size changed. - * \param geometry The new widget geometry. - */ -extern DECLSPEC void KW_SetWidgetGeometry(KW_Widget * widget, const KW_Rect * geometry); - -/** - * \brief Gets the widget geometry. - * \details Use this function to retrieve the current *relative* geometry of the widget. - * \param widget The widget to get the geometry from. - * \param geometry A KW_Rect pointer that will receive the @p widget geometry. - */ -extern DECLSPEC void KW_GetWidgetGeometry(const KW_Widget * widget, KW_Rect * geometry); - -/** - * \brief Gets the absolute widget geometry. - * \details Use this if you need to know the absolute widget geometry calculated taking its parents in consideration. - * It is useful inside the paint function of a widget. - * \param widget The widget to get the absolute geometry from. - * \param geometry A KW_Rect pointer that will receive the @p widget absolute geometry. - */ -extern DECLSPEC void KW_GetWidgetAbsoluteGeometry(const KW_Widget * widget, KW_Rect * geometry); - -/** - * \brief Gets the composed geometry of a widget. - * \details Returns the total area occupied by a widget and its children. Note that the position is - * still relative to its parent widget. - * \param widget The widget to get the compsoed geometry from. - * \param geometry A KW_Rect pointer that will receive the @p widget composed geometry. - */ -extern DECLSPEC void KW_GetWidgetComposedGeometry(const KW_Widget * widget, KW_Rect * composed); - -/** - * \brief Paint a widget and all of its children unless they are hidden. - * \details Iterates through all of the @p widget subtree calling their paint functions. - * If you wish to paint all widgets of a KW_GUI instance it is better to call - * `KW_Paint()` rather than this function. - * \param widget The widget to paint. - */ -extern DECLSPEC void KW_PaintWidget(KW_Widget * widget); - -/** - * \brief Moves widget at the back of the rendering list. - * \details Iterates through all of the @p widget subtree searching for a widget to - put it at the back of chidlren to render makeing it effectivly be on top. - * \param widget The widget to apply changes to. - */ -extern DECLSPEC void KW_BringToFront(KW_Widget * widget); - -/** - * \brief Moves GUI focus to given widget. - * \details Make given widget target of user input, notify previous target and fire events. - * \param widget The widget to set focused. - */ -extern DECLSPEC void KW_SetFocusedWidget(KW_Widget * widget); - -/* Stuff now related to handling of events (focus, mouse, keyboard, etc) */ - -/** - * \brief Block this widget from receiving input events (mouse, keyboard, touch, etc) - * \details You can use this function if you want to keep the widget from receiving input related events. - * The widget will not know if the cursor is over it, if a key was pressed, etc. - * - * If you have composite widgets and want the widgets on top to not steal mouse-over or press events - * from the widgets below this function might be useful to you. - * - * All children widgets will also have its input events blocked. - * *This is just a wrapper of KW_EnableWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS)* - * \param widget The widget that will stop receiving input evenets. - */ -extern DECLSPEC void KW_BlockWidgetInputEvents(KW_Widget * widget); - -/** - * \brief Unblocks this widget from receiving input events. - * \details See ::KW_BlockWidgetEvents. All children widgets will have its input events unblocked. - * *This is just a wrapper of KW_DisableWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS)* - * \param widget The widget that will now receive input events. - */ -extern DECLSPEC void KW_UnblockWidgetInputEvents(KW_Widget * widget); - -/** - * \brief Returns KW_TRUE if this widget is blocking input events. - * \param widget The widget to query. - * \details This function is a wrapper of KW_QueryWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS) - * \return KW_TRUE or KW_FALSE in case events are blocked or not. - */ -extern DECLSPEC KW_bool KW_IsWidgetInputEventsBlocked(KW_Widget * widget); - -extern DECLSPEC void KW_EnableWidgetHint(KW_Widget * widget, KW_WidgetHint hint); -extern DECLSPEC void KW_DisableWidgetHint(KW_Widget * widget, KW_WidgetHint hint); -extern DECLSPEC KW_bool KW_QueryWidgetHint(const KW_Widget * widget, KW_WidgetHint hint); - -/** - * \brief Adds a function that will be called whenever the mouse/cursor gets over the widget. - * \details If you want to know when the cursor is over the widget, you can add a handler to the list. - * \param widget The widget to add a KW_OnMouseOver handler. - * \param handler The KW_OnMouseOver function pointer. - */ -extern DECLSPEC void KW_AddWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler); - -/** - * \brief Remove a KW_OnMouseOver handler from a widget - * \details If you're not interested anymore in MouseOver events, remove your handler. - * \param widget The widget to remove the KW_OnMouseOver handler. - * \param handler The KW_OnMouseOver function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler); - - -/** - * \brief Adds a function that will be called whenever the mouse/cursor leaves the widget. - * \details If you want to know when the cursor lefts the widget geometry, you can add a handler to the list. - * \param widget The widget to add a KW_OnMouseLeave handler. - * \param handler The KW_OnMouseLeave function pointer. - */ -extern DECLSPEC void KW_AddWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler); - -/** - * \brief Remove a KW_OnMouseLeave handler from a widget - * \details If you're not interested anymore in MouseLeave events, remove your handler. - * \param widget The widget to remove the KW_OnMouseLeave handler. - * \param handler The KW_OnMouseLeave function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler); - -/** - * \brief Adds a function that will be called whenever the mouse/cursor clicks the widget. - * \details If you want to know when the user clicked in your widget and with which button, insert a callback :) - * \param widget The widget to add a KW_OnMouseDown handler. - * \param handler The KW_OnMouseDown function pointer. - */ -extern DECLSPEC void KW_AddWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler); - -/** - * \brief Remove a KW_OnMouseDown handler from a widget. - * \details If you're not interested anymore in MouseDown events, remove your handler. - * \param widget The widget to remove the KW_OnMouseDown handler. - * \param handler The KW_OnMouseDown function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler); - -/** - * \brief Adds a function that will be called whenever the mouse/cursor un-clicks the widget. - * \details If you want to know when the user released the cursor in your widget and with which button, insert a callback :) - * \param widget The widget to add a KW_OnMouseUp handler. - * \param handler The KW_OnMouseUp function pointer. - */ -extern DECLSPEC void KW_AddWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseUp handler); - -/** - * \brief Remove a KW_OnMouseUp handler from a widget. - * \details If you're not interested anymore in KW_OnMouseUp events, remove your handler. - * \param widget The widget to remove the KW_OnMouseUp handler. - * \param handler The KW_OnMouseUp function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseUp handler); - - -/** - * \brief Adds a function that will be called whenever the focus is gained by this widget. - * \details Focus usually happens when the user clicks on the widget or navigates via tab key. - * \param widget The widget to add a FocusGain handler. - * \param handler The OnFocusGain function pointer. - */ -extern DECLSPEC void KW_AddWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler); - -/** - * \brief Remove a KW_OnFocusGain handler from a widget. - * \details If you're not interested anymore in FocusGain events, remove your handler. - * \param widget The widget to remove the KW_OnFocusGain handler. - * \param handler The KW_OnFocusGain function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler); - -/** - * \brief Adds a function that will be called whenever the focus moves from this to another widget. - * \details If you want to be notified when the widget loses the focus, you should add a handler to it. - * \param widget The widget to add a FocusLose handler. - * \param handler The OnFocusLose function pointer. - */ -extern DECLSPEC void KW_AddWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler); - -/** - * \brief Remove a KW_OnFocusLose handler from a widget. - * \details If you're not interested anymore in FocusLose events, remove your handler. - * \param widget The widget to remove the KW_OnFocusLose handler. - * \param handler The KW_OnFocusLose function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler); - -/** - * \brief Adds a function that will be called when there's new text input. - * \details This handler will *only* be called if this widget is the focused widget *and* you called SDL_StartTextInput(). - * \param widget The widget to add a KW_OnTextInput handler. - * \param handler The KW_OnTextInput function pointer. - */ -extern DECLSPEC void KW_AddWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler); - - -/** - * \brief Remove a KW_OnTextInput handler from a widget. - * \details If you're not interested anymore in KW_OnTextInput events, remove your handler. - * \param widget The widget to remove the KW_OnTextInput handler. - * \param handler The KW_OnTextInput function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler); - - -/** - * \brief Adds a function that will be called when there's a key pressed. - * \details This handler will *only* be called if this widget is the focused widget. - * \param widget The widget to add a KW_OnKeyDown handler. - * \param handler The KW_OnKeyDown function pointer. - */ -extern DECLSPEC void KW_AddWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler); - - -/** - * \brief Remove a KW_OnKeyDown handler from a widget. - * \details If you're not interested anymore in KW_OnKeyDown events, remove your handler. - * \param widget The widget to remove the KW_OnKeyDown handler. - * \param handler The KW_OnKeyDown function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler); - -/** - * \brief Adds a function that will be called when there's a key released. - * \details This handler will *only* be called if this widget is the focused widget. - * \param widget The widget to add a KW_OnKeyUp handler. - * \param handler The KW_OnKeyUp function pointer. - */ -extern DECLSPEC void KW_AddWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler); - - -/** - * \brief Remove a KW_OnKeyUp handler from a widget. - * \details If you're not interested anymore in KW_OnKeyUp events, remove your handler. - * \param widget The widget to remove the KW_OnKeyUp handler. - * \param handler The KW_OnKeyUp function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler); - -/** - * \brief Adds a function that will be called when drag is starting over the widget. - * \details This handler is called after the cursor is pressed and then moved. - * \param widget The widget to add a KW_OnDragStart handler. - * \param handler The KW_OnDragStart function pointer. - */ -extern DECLSPEC void KW_AddWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler); - - -/** - * \brief Remove a KW_OnDragStart handler from a widget. - * \details If you're not interested anymore in KW_OnDragStart events, remove your handler. - * \param widget The widget to remove the KW_OnDragStart handler. - * \param handler The KW_OnDragStart function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler); - -/** - * \brief Adds a function to be called when a drag stops. - * \details The handler will be called only if the drag was started over this widget. - * \param widget The widget to add a KW_OnDragStop handler. - * \param handler The KW_OnDragStop function pointer. - */ -extern DECLSPEC void KW_AddWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler); - - -/** - * \brief Remove a KW_OnDragStop handler from a widget. - * \details If you're not interested anymore in KW_OnDragStop events, remove your handler. - * \param widget The widget to remove the KW_OnDragStop handler. - * \param handler The KW_OnDragStop function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler); - -/** - * \brief Adds a function to be called when a drag event occurs. - * \details The handler will be called only if the drag was started over this widget and the DragStart handler was called. - * \param widget The widget to add a KW_OnDragStop handler. - * \param handler The KW_OnDragStop function pointer. - */ -extern DECLSPEC void KW_AddWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler); - -/** - * \brief Adds a function to be called when this widget geometry is changed. - * \param widget The widget that has its geometry changed. - * \param handler The KW_OnGeometryChange function handler. - */ -extern DECLSPEC void KW_AddWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler); - -/** - * \brief Remove a KW_OnGeometryChange handler. - * \param widget The widget to remove the KW_OnGeometryChange handler. - * \param handler The KW_OnGeometryChange function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler); - -/** - * \brief Adds a function to call when this widget children count changes. - * \param widget The widget that has its children count changed. - * \param handler The KW_OnWidgetChildrenChange function handler. - */ -extern DECLSPEC void KW_AddWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler); - -/** - * \brief Remove a KW_OnWidgetChildrenChange handler. - * \param widget The widget to remove the KW_OnWidgetChildrenChange handler. - * \param handler The KW_OnWidgetChildrenChange function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler); - -/** - * \brief Remove a KW_OnDrag handler from a widget. - * \details If you're not interested anymore in KW_OnDrag events, remove your handler. - * \param widget The widget to remove the KW_OnDrag handler. - * \param handler The KW_OnDrag function pointer. - */ -extern DECLSPEC void KW_RemoveWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler); - -/** - * \brief Change the tileset used to render this widget. - * \details You are still responsible for freeing the previous tileset. - * \param widget The widget to change the tileset. - * \param tileset The new tileset surface. - */ -extern DECLSPEC void KW_SetWidgetTilesetSurface(KW_Widget * widget, KW_Surface * tileset); - -/** - * \brief Returns the current tileset being used by the widget. - * \details Keep in mind that this can be the same of the set in the KW_GUI instance. - * \param widget The widget to retrieve the tileset from. - * \returns A pointer to the KW_Texture being used as a tileset. - */ -extern DECLSPEC KW_Texture * KW_GetWidgetTilesetTexture(KW_Widget * widget); - -/** - * \brief Returns the current tileset being used by the widget. - * \details Keep in mind that this can be the same of the set in the KW_GUI instance. - * \param widget The widget to retrieve the tileset surface from. - * \returns A pointer to the KW_Texture being used as a tileset. - */ -extern DECLSPEC KW_Texture * KW_GetWidgetTilesetSurface(KW_Widget * widget); - -/** - * \brief Sets this widget to clip its children to its geometry. - * \details Both rendering and event calculation/reporting will be blocked for - * ALL the widgets in the tree. - * \param widget The widget that will have its children clipped or not. - * \param shouldclip If it should clip or not. - */ -extern DECLSPEC void KW_SetClipChildrenWidgets(KW_Widget * widget, KW_bool shouldclip); - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2014, Leonardo Guilherme de Freitas + All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef KW_WIDGET_H +#define KW_WIDGET_H + +#include "KW_macros.h" +#include "SDL.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The KW_Widget type represents a widget on the KW_GUI instance. + * \details Regardless of the widget type, they are all represented by this opaque type. + */ +struct KW_Widget; +typedef struct KW_Widget KW_Widget; + + +struct KW_GUI; +typedef struct KW_GUI KW_GUI; + +/* forward declarations of these */ +extern DECLSPEC SDL_Renderer * KW_GetRenderer(KW_GUI * gui); +extern DECLSPEC KW_GUI * KW_GetGUI(const KW_Widget * widget); + + + +typedef void (*KW_WidgetPaintFunction)(KW_Widget * widget); +typedef void (*KW_WidgetDestroyFunction)(KW_Widget * widget); + +/* mouse callbacks */ +typedef void (*KW_OnMouseOver)(KW_Widget * widget); +typedef void (*KW_OnMouseLeave)(KW_Widget * widget); +typedef void (*KW_OnMouseDown)(KW_Widget * widget, int button); +typedef void (*KW_OnMouseUp)(KW_Widget * widget, int button); + +/* drag callbacks */ +typedef void (*KW_OnDragStart)(KW_Widget * widget, int x, int y); +typedef void (*KW_OnDragStop)(KW_Widget * widget, int x, int y); +typedef void (*KW_OnDrag)(KW_Widget * widget, int x, int y, int relx, int rely); + +/* focus callbacks */ +typedef void (*KW_OnFocusGain)(KW_Widget * widget); +typedef void (*KW_OnFocusLose)(KW_Widget * widget); + +/* text and keyboard callbacks */ +typedef void (*KW_OnTextInput)(KW_Widget * widget, const char * text); +typedef void (*KW_OnKeyDown)(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); +typedef void (*KW_OnKeyUp)(KW_Widget * widget, SDL_Keycode sym, SDL_Scancode code); + +/* widget internal events */ +typedef void (*KW_OnGeometryChange)(KW_Widget * widget, const SDL_Rect * newgeom, const SDL_Rect * oldgeom); + +/** + * \brief The event type when the children array changes. + * \details Whenever the direct children number of an array changes, this + * enum is used to indicate if it was insertion or a removal. + */ +typedef enum KW_WidgetChildrenChangeEvent { + KW_CHILDRENCHANGE_ADDED, + KW_CHILDRENCHANGE_REMOVED +} KW_WidgetChildrenChangeEvent; + + +typedef void (*KW_OnWidgetChildrenChange)(KW_Widget * widget, KW_WidgetChildrenChangeEvent what, KW_Widget * child); + +/** + * \brief The KW_WidgetType enumeration represents available widget types. + * \details Every widget created must set a widget type even if its a custom widget. + */ +typedef enum KW_WidgetType { + KW_WIDGETTYPE_NONE, + KW_WIDGETTYPE_FRAME, + KW_WIDGETTYPE_LABEL, + KW_WIDGETTYPE_BUTTON, + KW_WIDGETTYPE_EDITBOX, + KW_WIDGETTYPE_SCROLLBOX, + KW_WIDGETTYPE_CUSTOM0 = 0x100000, + KW_WIDGETTYPE_CUSTOM1, + KW_WIDGETTYPE_CUSTOM2, + KW_WIDGETTYPE_CUSTOM3, + KW_WIDGETTYPE_CUSTOM4, + KW_WIDGETTYPE_CUSTOM5, + KW_WIDGETTYPE_CUSTOM6, + KW_WIDGETTYPE_CUSTOM7, + KW_WIDGETTYPE_CUSTOM8, + KW_WIDGETTYPE_CUSTOM9, + KW_WIDGETTYPE_CUSTOM10, + KW_WIDGETTYPE_CUSTOM11, + KW_WIDGETTYPE_CUSTOM12, + KW_WIDGETTYPE_CUSTOM13, + KW_WIDGETTYPE_CUSTOM14, + KW_WIDGETTYPE_CUSTOM15, + KW_WIDGETTYPE_CUSTOM16, + KW_WIDGETTYPE_CUSTOM17, + KW_WIDGETTYPE_CUSTOM18, + KW_WIDGETTYPE_CUSTOM19, + KW_WIDGETTYPE_CUSTOM20 +} KW_WidgetType; + +/** + * \brief Set of hints to control how this widget operates. + * \details These hints can be queried by the widget implementation to change + * its behaviour. They are also used to change KiWi's behaviour when + * propagating input events, etc. + */ +typedef enum KW_WidgetHint { + /** Allow widgets to stretch tiles */ + KW_WIDGETHINT_ALLOWTILESTRETCH = 1 << 0, + + /** Makes KiWi avoid reporting input events to this widget and its children + * widget */ + KW_WIDGETHINT_BLOCKINPUTEVENTS = 1 << 1, + + /** Makes KiWi avoid reporting input event to this widget but still passes to + * its children widgets */ + KW_WIDGETHINT_IGNOREINPUTEVENTS = 1 << 2, + + /** Hints widget implementations that, if possible, the user wants a + * frameless version of it */ + KW_WIDGETHINT_FRAMELESS = 1 << 3 +} KW_WidgetHint; + +/** + * \brief Creates a new custom widget instance. + * \details If you want to provide a new custom widget this is the function that you should call. + * All KW_Widget instances are built using this class, if you should need additional widget + * information you can use the data parameter. + * + * The widgetpaint function is called to paint the widget after the parent widget has been painted, never + * before, so you are garanteed to be rendering on top of it. + * + * Widget geometry is relative to its parent. Consider the following figure: + * + * \verbatim + * + * 10x10.---------------------------. + * | Root Widget | + * | | + * | | + * 10x30.------------. | + * | |Root's Child| | + * | | | | + * | | 40x20.---------------. | + * | | | Child's Child | | + * | | | | | + * | | | | | + * | | `---------------´80x40 + * | | | | + * | `------------´70x90 | + * | | + * `-----------------------------´150x150 + * + * Geometry is represented as XxY+WxH. + * + * \endverbatim + * + * The root widget starts at 10x10. The child widget starts at 10x30 *relative* to the root widget. That means that + * its absolute position is actually 20x40! The 'Child's Child' widget starts at 40x20 relative to its parent but its + * absolute position is (10 + 10 + 40, 10 + 30 + 20) = 60x60. If the parent widget moves, all its children move together. + * + * Widgets also have a composed geometry that is calculated by considering each child geometry. They represent the total + * area occupied by a widget and its children. In the above picture, + * the 'Root's Child' widget composed geometry is calculated by taking each of its children composed geometry and checking + * if they are out of the current widget composed geometry. Since 'Child's Child' width and height is out of 'Root's Child' + * geometry, 'Root's Child' composed geometry ends up not being 10x30+70x90, but rather 10x30+(40+80+70x90) = 10x30+120x90. + * Note the width was updated but not the height. + * + * The absolute geometry of a widget is calculating by iterating the parent tree and adding their position (x and y). + * + * \param gui The KW_GUI instace that will hold this widget in its widget tree. + * \param parent The parent widget. + * \param type The type of this widget. + * \param geometry The geometry of this widget *relative* to its parent. + * \param widgetpaing The paint function of this widget. + * \param widgetdestroy The destroy function of this widget. + * \param data Any private data associated with this widget. Mostly to be used by widget implementations. + * \returns The new widget. + */ +extern DECLSPEC KW_Widget * KW_CreateWidget(KW_GUI * gui, + KW_Widget * parent, + KW_WidgetType type, + const SDL_Rect * geometry, + KW_WidgetPaintFunction widgetpaint, + KW_WidgetDestroyFunction widgetdestroy, + void * data); + + +/** + * \brief Change the parent of a widget to another parent. + * \details Remove \p widget as a child from its current parent and adds it as a child to \p parent. + * Every child of \p widget will then belong to the new \p parent tree. Note that \p widget + * geometry is **NOT** updated to keep it in the previous absolute position. You should call + * KW_SetWidgetGeometry() to update it. + * + * Keep in mind that this is one of the costliest functions to call in the KiWi library as it + * might involve memory reallocation both in the previous and in the new parent widget. The composed + * geometry also needs to be updated in both parents in a chain that might go as high as the root widget. + * You should avoid widget reparenting if you can. + * + * To make the widget a top-level widget you should pass \c NULL as the @p parent parameter. + * + * \param widget The widget that will have its parent changed. + * \param parent The new \p widget parent. + */ +extern DECLSPEC void KW_ReparentWidget(KW_Widget * widget, KW_Widget * parent); + +/** + * \brief Retrieves the parent widget of a widget. + * \param widget The KW_Widget instance to retrieve the parent from. + * \returns The parent widget or NULL if its a top-level widget. + */ +extern DECLSPEC KW_Widget * KW_GetWidgetParent(const KW_Widget * widget); + +/** + * \brief Returns an array of all childrens of this widget. + * \details The returned array is the same as stored internally and its contents + * can change if any reparenting is done after calling this function, + * thus, you should not store its value. +* \param widget The widget to return childrens from. + * \param[out] count If not NULL, the unsigned int pointed by it will have the + * children count of the widget. + * \returns An array of constant pointers to all childrens of \p widget. + */ +extern DECLSPEC KW_Widget * const * KW_GetWidgetChildren(const KW_Widget * widget, unsigned int * count); + +/** + * \brief Retrieves the current data associated with a widget. + * \details If you are implementing a custom widget, you must call this function to access the data you + * set up previously when the widget was created. + * \param widget The widget to retrieve the data from. + * \param type The widget type you're expecting @p widget to be + * \returns The data pointer or NULL if the widget types don't match. + */ +extern DECLSPEC void * KW_GetWidgetData(const KW_Widget * widget, KW_WidgetType type); + + +/** + * \brief Sets a pointer to user-specific data to be read later. + * \details Use this if you want to store user-specific state in this widget + * that could be shared among callbacks. Widget implementations should + * not use this. There's no check if it had any user data before, use + * with caution. + * \param widget The widget to set the user data. + * \param userdata The associated user data + */ +extern DECLSPEC void KW_SetWidgetUserData(KW_Widget * widget, void * userdata); + +/** + * \brief Returns the associated user data of a widget. + * \details Use this function to access a previously stored user data pointer. + * \param widget The widget to get userdata from. + * \returns The usertdata pointer + */ +extern DECLSPEC void * KW_GetWidgetUserData(const KW_Widget * widget); + +/** + * \brief Destroys a widget and free its resources. + * \details Any custom resource that you set (fonts, custom textures, etc) needs to be freed by you unless specified otherwise. + * \param widget The widget to destroy. + * \param destroychildren Set to 1 if you want also to destroy all childrens (and their childrens) of this widget. If not, they will be + * reparented to @p widget parent. + */ +extern DECLSPEC void KW_DestroyWidget(KW_Widget * widget, int destroychildren); + +/** + * \brief Returns the associated KW_GUI instance of a widget. + * \details If you have a widget instance, this is the means of retrieving its KW_GUI instance. + * \param widget The widget to get the KW_GUI instance from. + * \return The KW_GUI instance associated with the widget. + */ +extern DECLSPEC KW_GUI * KW_GetWidgetGUI(const KW_Widget * widget); + +/** + * \brief Returns the SDL_Renderer associated with a KW_GUI instance that the @p widget is associated with. + * \details This is a helper function and its effects are the same of `KW_GetRenderer(KW_GetWidgetGUI(widget))` + * \param widget The widget to get the SDL_Renderer instance from. + * \returns The associated SDL_Renderer instance. + */ +extern DECLSPEC SDL_Renderer * KW_GetWidgetRenderer(const KW_Widget * widget); + +/** + * \brief Sets a new geometry for a widget. + * \details Use this function if you need to change the widget relative position or its size. + * \param widget The widget that will have its size changed. + * \param geometry The new widget geometry. + */ +extern DECLSPEC void KW_SetWidgetGeometry(KW_Widget * widget, const SDL_Rect * geometry); + +/** + * \brief Gets the widget geometry. + * \details Use this function to retrieve the current *relative* geometry of the widget. + * \param widget The widget to get the geometry from. + * \param geometry A SDL_Rect pointer that will receive the @p widget geometry. + */ +extern DECLSPEC void KW_GetWidgetGeometry(const KW_Widget * widget, SDL_Rect * geometry); + +/** + * \brief Gets the absolute widget geometry. + * \details Use this if you need to know the absolute widget geometry calculated taking its parents in consideration. + * It is useful inside the paint function of a widget. + * \param widget The widget to get the absolute geometry from. + * \param geometry A SDL_Rect pointer that will receive the @p widget absolute geometry. + */ +extern DECLSPEC void KW_GetWidgetAbsoluteGeometry(const KW_Widget * widget, SDL_Rect * geometry); + +/** + * \brief Gets the composed geometry of a widget. + * \details Returns the total area occupied by a widget and its children. Note that the position is + * still relative to its parent widget. + * \param widget The widget to get the compsoed geometry from. + * \param geometry A SDL_Rect pointer that will receive the @p widget composed geometry. + */ +extern DECLSPEC void KW_GetWidgetComposedGeometry(const KW_Widget * widget, SDL_Rect * composed); + +/** + * \brief Paint a widget and all of its children unless they are hidden. + * \details Iterates through all of the @p widget subtree calling their paint functions. + * If you wish to paint all widgets of a KW_GUI instance it is better to call + * `KW_Paint()` rather than this function. + * \param widget The widget to paint. + */ +extern DECLSPEC void KW_PaintWidget(KW_Widget * widget); + +/** + * \brief Moves widget at the back of the rendering list. + * \details Iterates through all of the @p widget subtree searching for a widget to + put it at the back of chidlren to render makeing it effectivly be on top. + * \param widget The widget to apply changes to. + */ +extern DECLSPEC void KW_BringToFront(KW_Widget * widget); + +/** + * \brief Moves GUI focus to given widget. + * \details Make given widget target of user input, notify previous target and fire events. + * \param widget The widget to set focused. + */ +extern DECLSPEC void KW_SetFocusedWidget(KW_Widget * widget); + +/* Stuff now related to handling of events (focus, mouse, keyboard, etc) */ + +/** + * \brief Block this widget from receiving input events (mouse, keyboard, touch, etc) + * \details You can use this function if you want to keep the widget from receiving input related events. + * The widget will not know if the cursor is over it, if a key was pressed, etc. + * + * If you have composite widgets and want the widgets on top to not steal mouse-over or press events + * from the widgets below this function might be useful to you. + * + * All children widgets will also have its input events blocked. + * *This is just a wrapper of KW_EnableWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS)* + * \param widget The widget that will stop receiving input evenets. + */ +extern DECLSPEC void KW_BlockWidgetInputEvents(KW_Widget * widget); + +/** + * \brief Unblocks this widget from receiving input events. + * \details See ::KW_BlockWidgetEvents. All children widgets will have its input events unblocked. + * *This is just a wrapper of KW_DisableWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS)* + * \param widget The widget that will now receive input events. + */ +extern DECLSPEC void KW_UnblockWidgetInputEvents(KW_Widget * widget); + +/** + * \brief Returns SDL_TRUE if this widget is blocking input events. + * \param widget The widget to query. + * \details This function is a wrapper of KW_QueryWidgetHint(w, KW_WIDGETHINT_BLOCKINPUTEVENTS) + * \return SDL_TRUE or SDL_FALSE in case events are blocked or not. + */ +extern DECLSPEC SDL_bool KW_IsWidgetInputEventsBlocked(KW_Widget * widget); + +extern DECLSPEC void KW_EnableWidgetHint(KW_Widget * widget, KW_WidgetHint hint); +extern DECLSPEC void KW_DisableWidgetHint(KW_Widget * widget, KW_WidgetHint hint); +extern DECLSPEC SDL_bool KW_QueryWidgetHint(const KW_Widget * widget, KW_WidgetHint hint); + +/** + * \brief Adds a function that will be called whenever the mouse/cursor gets over the widget. + * \details If you want to know when the cursor is over the widget, you can add a handler to the list. + * \param widget The widget to add a KW_OnMouseOver handler. + * \param handler The KW_OnMouseOver function pointer. + */ +extern DECLSPEC void KW_AddWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler); + +/** + * \brief Remove a KW_OnMouseOver handler from a widget + * \details If you're not interested anymore in MouseOver events, remove your handler. + * \param widget The widget to remove the KW_OnMouseOver handler. + * \param handler The KW_OnMouseOver function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetMouseOverHandler(KW_Widget * widget, KW_OnMouseOver handler); + + +/** + * \brief Adds a function that will be called whenever the mouse/cursor leaves the widget. + * \details If you want to know when the cursor lefts the widget geometry, you can add a handler to the list. + * \param widget The widget to add a KW_OnMouseLeave handler. + * \param handler The KW_OnMouseLeave function pointer. + */ +extern DECLSPEC void KW_AddWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler); + +/** + * \brief Remove a KW_OnMouseLeave handler from a widget + * \details If you're not interested anymore in MouseLeave events, remove your handler. + * \param widget The widget to remove the KW_OnMouseLeave handler. + * \param handler The KW_OnMouseLeave function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetMouseLeaveHandler(KW_Widget * widget, KW_OnMouseLeave handler); + +/** + * \brief Adds a function that will be called whenever the mouse/cursor clicks the widget. + * \details If you want to know when the user clicked in your widget and with which button, insert a callback :) + * \param widget The widget to add a KW_OnMouseDown handler. + * \param handler The KW_OnMouseDown function pointer. + */ +extern DECLSPEC void KW_AddWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler); + +/** + * \brief Remove a KW_OnMouseDown handler from a widget. + * \details If you're not interested anymore in MouseDown events, remove your handler. + * \param widget The widget to remove the KW_OnMouseDown handler. + * \param handler The KW_OnMouseDown function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetMouseDownHandler(KW_Widget * widget, KW_OnMouseDown handler); + +/** + * \brief Adds a function that will be called whenever the mouse/cursor un-clicks the widget. + * \details If you want to know when the user released the cursor in your widget and with which button, insert a callback :) + * \param widget The widget to add a KW_OnMouseUp handler. + * \param handler The KW_OnMouseUp function pointer. + */ +extern DECLSPEC void KW_AddWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseUp handler); + +/** + * \brief Remove a KW_OnMouseUp handler from a widget. + * \details If you're not interested anymore in KW_OnMouseUp events, remove your handler. + * \param widget The widget to remove the KW_OnMouseUp handler. + * \param handler The KW_OnMouseUp function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetMouseUpHandler(KW_Widget * widget, KW_OnMouseUp handler); + + +/** + * \brief Adds a function that will be called whenever the focus is gained by this widget. + * \details Focus usually happens when the user clicks on the widget or navigates via tab key. + * \param widget The widget to add a FocusGain handler. + * \param handler The OnFocusGain function pointer. + */ +extern DECLSPEC void KW_AddWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler); + +/** + * \brief Remove a KW_OnFocusGain handler from a widget. + * \details If you're not interested anymore in FocusGain events, remove your handler. + * \param widget The widget to remove the KW_OnFocusGain handler. + * \param handler The KW_OnFocusGain function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetFocusGainHandler(KW_Widget * widget, KW_OnFocusGain handler); + +/** + * \brief Adds a function that will be called whenever the focus moves from this to another widget. + * \details If you want to be notified when the widget loses the focus, you should add a handler to it. + * \param widget The widget to add a FocusLose handler. + * \param handler The OnFocusLose function pointer. + */ +extern DECLSPEC void KW_AddWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler); + +/** + * \brief Remove a KW_OnFocusLose handler from a widget. + * \details If you're not interested anymore in FocusLose events, remove your handler. + * \param widget The widget to remove the KW_OnFocusLose handler. + * \param handler The KW_OnFocusLose function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetFocusLoseHandler(KW_Widget * widget, KW_OnFocusLose handler); + +/** + * \brief Adds a function that will be called when there's new text input. + * \details This handler will *only* be called if this widget is the focused widget *and* you called SDL_StartTextInput(). + * \param widget The widget to add a KW_OnTextInput handler. + * \param handler The KW_OnTextInput function pointer. + */ +extern DECLSPEC void KW_AddWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler); + + +/** + * \brief Remove a KW_OnTextInput handler from a widget. + * \details If you're not interested anymore in KW_OnTextInput events, remove your handler. + * \param widget The widget to remove the KW_OnTextInput handler. + * \param handler The KW_OnTextInput function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetTextInputHandler(KW_Widget * widget, KW_OnTextInput handler); + + +/** + * \brief Adds a function that will be called when there's a key pressed. + * \details This handler will *only* be called if this widget is the focused widget. + * \param widget The widget to add a KW_OnKeyDown handler. + * \param handler The KW_OnKeyDown function pointer. + */ +extern DECLSPEC void KW_AddWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler); + + +/** + * \brief Remove a KW_OnKeyDown handler from a widget. + * \details If you're not interested anymore in KW_OnKeyDown events, remove your handler. + * \param widget The widget to remove the KW_OnKeyDown handler. + * \param handler The KW_OnKeyDown function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetKeyDownHandler(KW_Widget * widget, KW_OnKeyDown handler); + +/** + * \brief Adds a function that will be called when there's a key released. + * \details This handler will *only* be called if this widget is the focused widget. + * \param widget The widget to add a KW_OnKeyUp handler. + * \param handler The KW_OnKeyUp function pointer. + */ +extern DECLSPEC void KW_AddWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler); + + +/** + * \brief Remove a KW_OnKeyUp handler from a widget. + * \details If you're not interested anymore in KW_OnKeyUp events, remove your handler. + * \param widget The widget to remove the KW_OnKeyUp handler. + * \param handler The KW_OnKeyUp function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetKeyUpHandler(KW_Widget * widget, KW_OnKeyUp handler); + +/** + * \brief Adds a function that will be called when drag is starting over the widget. + * \details This handler is called after the cursor is pressed and then moved. + * \param widget The widget to add a KW_OnDragStart handler. + * \param handler The KW_OnDragStart function pointer. + */ +extern DECLSPEC void KW_AddWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler); + + +/** + * \brief Remove a KW_OnDragStart handler from a widget. + * \details If you're not interested anymore in KW_OnDragStart events, remove your handler. + * \param widget The widget to remove the KW_OnDragStart handler. + * \param handler The KW_OnDragStart function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetDragStartHandler(KW_Widget * widget, KW_OnDragStart handler); + +/** + * \brief Adds a function to be called when a drag stops. + * \details The handler will be called only if the drag was started over this widget. + * \param widget The widget to add a KW_OnDragStop handler. + * \param handler The KW_OnDragStop function pointer. + */ +extern DECLSPEC void KW_AddWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler); + + +/** + * \brief Remove a KW_OnDragStop handler from a widget. + * \details If you're not interested anymore in KW_OnDragStop events, remove your handler. + * \param widget The widget to remove the KW_OnDragStop handler. + * \param handler The KW_OnDragStop function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetDragStopHandler(KW_Widget * widget, KW_OnDragStop handler); + +/** + * \brief Adds a function to be called when a drag event occurs. + * \details The handler will be called only if the drag was started over this widget and the DragStart handler was called. + * \param widget The widget to add a KW_OnDragStop handler. + * \param handler The KW_OnDragStop function pointer. + */ +extern DECLSPEC void KW_AddWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler); + +/** + * \brief Adds a function to be called when this widget geometry is changed. + * \param widget The widget that has its geometry changed. + * \param handler The KW_OnGeometryChange function handler. + */ +extern DECLSPEC void KW_AddWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler); + +/** + * \brief Remove a KW_OnGeometryChange handler. + * \param widget The widget to remove the KW_OnGeometryChange handler. + * \param handler The KW_OnGeometryChange function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetGeometryChangeHandler(KW_Widget * widget, KW_OnGeometryChange handler); + +/** + * \brief Adds a function to call when this widget children count changes. + * \param widget The widget that has its children count changed. + * \param handler The KW_OnWidgetChildrenChange function handler. + */ +extern DECLSPEC void KW_AddWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler); + +/** + * \brief Remove a KW_OnWidgetChildrenChange handler. + * \param widget The widget to remove the KW_OnWidgetChildrenChange handler. + * \param handler The KW_OnWidgetChildrenChange function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetChildrenChangeHandler(KW_Widget * widget, KW_OnWidgetChildrenChange handler); + +/** + * \brief Remove a KW_OnDrag handler from a widget. + * \details If you're not interested anymore in KW_OnDrag events, remove your handler. + * \param widget The widget to remove the KW_OnDrag handler. + * \param handler The KW_OnDrag function pointer. + */ +extern DECLSPEC void KW_RemoveWidgetDragHandler(KW_Widget * widget, KW_OnDrag handler); + +/** + * \brief Change the tileset used to render this widget. + * \details You are still responsible for freeing the previous tileset. + * \param widget The widget to change the tileset. + * \param tileset The new tileset surface. + */ +extern DECLSPEC void KW_SetWidgetTilesetSurface(KW_Widget * widget, SDL_Surface * tileset); + +/** + * \brief Returns the current tileset being used by the widget. + * \details Keep in mind that this can be the same of the set in the KW_GUI instance. + * \param widget The widget to retrieve the tileset from. + * \returns A pointer to the SDL_Texture being used as a tileset. + */ +extern DECLSPEC SDL_Texture * KW_GetWidgetTilesetTexture(KW_Widget * widget); + +/** + * \brief Returns the current tileset being used by the widget. + * \details Keep in mind that this can be the same of the set in the KW_GUI instance. + * \param widget The widget to retrieve the tileset surface from. + * \returns A pointer to the SDL_Surface being used as a tileset. + */ +extern DECLSPEC SDL_Surface * KW_GetWidgetTilesetSurface(KW_Widget * widget); + +/** + * \brief Sets this widget to clip its children to its geometry. + * \details Both rendering and event calculation/reporting will be blocked for + * ALL the widgets in the tree. + * \param widget The widget that will have its children clipped or not. + * \param shouldclip If it should clip or not. + */ +extern DECLSPEC void KW_SetClipChildrenWidgets(KW_Widget * widget, SDL_bool shouldclip); + +extern DECLSPEC void KW_SetWidgetHidden(KW_Widget * widget, SDL_bool hidden); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/KW_widget_eventhandlers.c b/src/KW_widget_eventhandlers.c index be9b78e..d24a2c3 100644 --- a/src/KW_widget_eventhandlers.c +++ b/src/KW_widget_eventhandlers.c @@ -1,44 +1,44 @@ -#include "KW_widget_internal.h" - -void AddWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler) { - /* don't add multiple mouse over handlers */ - unsigned int * count = &(widget->eventhandlers[handlertype].count); - - /* check if handler is there */ - int i; - for (i = 0; i < *count; ++i) { - if (widget->eventhandlers[handlertype].handlers[i] == handler) - return; - } - - /* add the handler then */ - (*count)++; - widget->eventhandlers[handlertype].handlers = realloc(widget->eventhandlers[handlertype].handlers, sizeof(void *) * (*count)); - widget->eventhandlers[handlertype].handlers[(*count) - 1] = handler; -} - -void RemoveWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler) { - int i, j; - unsigned int * count = &(widget->eventhandlers[handlertype].count); - - /* iterate to find the position of widget */ - for (i = 0; i < *count; i++) { - if (widget->eventhandlers[handlertype].handlers[i] == handler) { - j = i; - } - - /* move everything in front of it */ - if (j >= 0 && i + 1 < *count) { - widget->eventhandlers[handlertype].handlers[i] = widget->eventhandlers[handlertype].handlers[i+1]; - } - } - - /* realloc children array */ - (*count)--; - if (*count <= 0) { - free(widget->eventhandlers[handlertype].handlers); - widget->eventhandlers[handlertype].handlers = NULL; - } - else - widget->eventhandlers[handlertype].handlers = realloc(widget->eventhandlers[handlertype].handlers, *count * sizeof(void *)); -} +#include "KW_widget_internal.h" + +void AddWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler) { + /* don't add multiple mouse over handlers */ + unsigned int * count = &(widget->eventhandlers[handlertype].count); + + /* check if handler is there */ + int i; + for (i = 0; i < *count; ++i) { + if (widget->eventhandlers[handlertype].handlers[i] == handler) + return; + } + + /* add the handler then */ + (*count)++; + widget->eventhandlers[handlertype].handlers = realloc(widget->eventhandlers[handlertype].handlers, sizeof(void *) * (*count)); + widget->eventhandlers[handlertype].handlers[(*count) - 1] = handler; +} + +void RemoveWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler) { + int i, j; + unsigned int * count = &(widget->eventhandlers[handlertype].count); + + /* iterate to find the position of widget */ + for (i = 0; i < *count; i++) { + if (widget->eventhandlers[handlertype].handlers[i] == handler) { + j = i; + } + + /* move everything in front of it */ + if (j >= 0 && i + 1 < *count) { + widget->eventhandlers[handlertype].handlers[i] = widget->eventhandlers[handlertype].handlers[i+1]; + } + } + + /* realloc children array */ + (*count)--; + if (*count <= 0) { + free(widget->eventhandlers[handlertype].handlers); + widget->eventhandlers[handlertype].handlers = NULL; + } + else + widget->eventhandlers[handlertype].handlers = realloc(widget->eventhandlers[handlertype].handlers, *count * sizeof(void *)); +} diff --git a/src/KW_widget_internal.h b/src/KW_widget_internal.h index 30727e0..c8c759c 100644 --- a/src/KW_widget_internal.h +++ b/src/KW_widget_internal.h @@ -1,67 +1,68 @@ -#ifndef KW_WIDGET_INTERNAL -#define KW_WIDGET_INTERNAL - -#include "KW_widget.h" - -struct KW_GUI; - -typedef enum KW_WidgetEventHandlerType { - KW_ON_MOUSEOVER, - KW_ON_MOUSELEAVE, - KW_ON_MOUSEDOWN, - KW_ON_MOUSEUP, - KW_ON_FOCUSGAIN, - KW_ON_FOCUSLOSE, - KW_ON_TEXTINPUT, - KW_ON_KEYDOWN, - KW_ON_KEYUP, - KW_ON_DRAGSTART, - KW_ON_DRAGSTOP, - KW_ON_DRAG, - KW_ON_GEOMETRYCHANGED, - KW_ON_CHILDRENCHANGE, - KW_EVENTHANDLER_TOTAL -} KW_WidgetEventHandlerType; - -typedef void (*WidgetHandler)(void); - -void AddWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler); -void RemoveWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler); - -struct KW_Widget { - KW_WidgetType type; - unsigned int childrencount; - struct KW_GUI * gui; - KW_Rect absolute; - KW_Rect geometry; - KW_Rect composed; - unsigned int hints; - - struct KW_Widget ** children; - struct KW_Widget * parent; - - - KW_Texture * tilesettexture; - KW_Texture * tilesetsurface; - - void (*paint)(KW_Widget *); - void (*destroy)(KW_Widget *); - - struct { - WidgetHandler * handlers; - unsigned int count; - } eventhandlers[KW_EVENTHANDLER_TOTAL]; - - - KW_Rect oldcliprect; - KW_bool clipchildren; - - void * userdata; - void * privdata; -}; - -KW_Widget * AllocWidget(); - -void FreeWidget(KW_Widget * widget, int freechildren); - -#endif +#ifndef KW_WIDGET_INTERNAL +#define KW_WIDGET_INTERNAL + +#include "KW_widget.h" + +struct KW_GUI; + +typedef enum KW_WidgetEventHandlerType { + KW_ON_MOUSEOVER, + KW_ON_MOUSELEAVE, + KW_ON_MOUSEDOWN, + KW_ON_MOUSEUP, + KW_ON_FOCUSGAIN, + KW_ON_FOCUSLOSE, + KW_ON_TEXTINPUT, + KW_ON_KEYDOWN, + KW_ON_KEYUP, + KW_ON_DRAGSTART, + KW_ON_DRAGSTOP, + KW_ON_DRAG, + KW_ON_GEOMETRYCHANGED, + KW_ON_CHILDRENCHANGE, + KW_EVENTHANDLER_TOTAL +} KW_WidgetEventHandlerType; + +typedef void (*WidgetHandler)(void); + +void AddWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler); +void RemoveWidgetHandler(KW_Widget * widget, KW_WidgetEventHandlerType handlertype, WidgetHandler handler); + +struct KW_Widget { + KW_WidgetType type; + unsigned int childrencount; + struct KW_GUI * gui; + SDL_Rect absolute; + SDL_Rect geometry; + SDL_Rect composed; + Uint32 hints; + + struct KW_Widget ** children; + struct KW_Widget * parent; + + + SDL_Texture * tilesettexture; + SDL_Surface * tilesetsurface; + + void (*paint)(KW_Widget *); + void (*destroy)(KW_Widget *); + + struct { + WidgetHandler * handlers; + unsigned int count; + } eventhandlers[KW_EVENTHANDLER_TOTAL]; + + + SDL_Rect oldcliprect; + SDL_bool clipchildren; + SDL_bool hidden; + + void * userdata; + void * privdata; +}; + +KW_Widget * AllocWidget(); + +void FreeWidget(KW_Widget * widget, int freechildren); + +#endif diff --git a/src/utf8.c b/src/utf8.c index 300d264..8b9cc00 100644 --- a/src/utf8.c +++ b/src/utf8.c @@ -1,395 +1,395 @@ -/* - Basic UTF-8 manipulation routines - by Jeff Bezanson - placed in the public domain Fall 2005 - - This code is designed to provide the utilities you need to manipulate - UTF-8 as an internal string encoding. These functions do not perform the - error checking normally needed when handling UTF-8 data, so if you happen - to be from the Unicode Consortium you will want to flay me alive. - I do this because error checking can be performed at the boundaries (I/O), - with these routines reserved for higher performance on data known to be - valid. -*/ -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#else -#include -#endif - -#include "utf8.h" - -static const uint32_t offsetsFromUTF8[6] = { - 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL -}; - -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* returns length of next utf-8 sequence */ -int u8_seqlen(char c) -{ - return trailingBytesForUTF8[(unsigned int)(unsigned char)c] + 1; -} - -/* conversions without error checking - only works for valid UTF-8, i.e. no 5- or 6-byte sequences - srcsz = source size in bytes, or -1 if 0-terminated - sz = dest size in # of wide characters - - returns # characters converted - dest will always be L'\0'-terminated, even if there isn't enough room - for all the characters. - if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. -*/ -int u8_toucs(uint32_t *dest, int sz, char *src, int srcsz) -{ - uint32_t ch; - char *src_end = src + srcsz; - int nb; - int i=0; - - while (i < sz-1) { - nb = trailingBytesForUTF8[(unsigned char)*src]; - if (srcsz == -1) { - if (*src == 0) - goto done_toucs; - } - else { - if (src + nb >= src_end) - goto done_toucs; - } - ch = 0; - switch (nb) { - /* these fall through deliberately */ - case 3: ch += (unsigned char)*src++; ch <<= 6; - case 2: ch += (unsigned char)*src++; ch <<= 6; - case 1: ch += (unsigned char)*src++; ch <<= 6; - case 0: ch += (unsigned char)*src++; - } - ch -= offsetsFromUTF8[nb]; - dest[i++] = ch; - } - done_toucs: - dest[i] = 0; - return i; -} - -/* srcsz = number of source characters, or -1 if 0-terminated - sz = size of dest buffer in bytes - - returns # characters converted - dest will only be '\0'-terminated if there is enough space. this is - for consistency; imagine there are 2 bytes of space left, but the next - character requires 3 bytes. in this case we could NUL-terminate, but in - general we can't when there's insufficient space. therefore this function - only NUL-terminates if all the characters fit, and there's space for - the NUL as well. - the destination string will never be bigger than the source string. -*/ -int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz) -{ - uint32_t ch; - int i = 0; - char *dest_end = dest + sz; - - while (srcsz<0 ? src[i]!=0 : i < srcsz) { - ch = src[i]; - if (ch < 0x80) { - if (dest >= dest_end) - return i; - *dest++ = (char)ch; - } - else if (ch < 0x800) { - if (dest >= dest_end-1) - return i; - *dest++ = (ch>>6) | 0xC0; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x10000) { - if (dest >= dest_end-2) - return i; - *dest++ = (ch>>12) | 0xE0; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x110000) { - if (dest >= dest_end-3) - return i; - *dest++ = (ch>>18) | 0xF0; - *dest++ = ((ch>>12) & 0x3F) | 0x80; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - i++; - } - if (dest < dest_end) - *dest = '\0'; - return i; -} - -int u8_wc_toutf8(char *dest, uint32_t ch) -{ - if (ch < 0x80) { - dest[0] = (char)ch; - return 1; - } - if (ch < 0x800) { - dest[0] = (ch>>6) | 0xC0; - dest[1] = (ch & 0x3F) | 0x80; - return 2; - } - if (ch < 0x10000) { - dest[0] = (ch>>12) | 0xE0; - dest[1] = ((ch>>6) & 0x3F) | 0x80; - dest[2] = (ch & 0x3F) | 0x80; - return 3; - } - if (ch < 0x110000) { - dest[0] = (ch>>18) | 0xF0; - dest[1] = ((ch>>12) & 0x3F) | 0x80; - dest[2] = ((ch>>6) & 0x3F) | 0x80; - dest[3] = (ch & 0x3F) | 0x80; - return 4; - } - return 0; -} - -/* charnum => byte offset */ -int u8_offset(char *str, int charnum) -{ - int offs=0; - - while (charnum > 0 && str[offs]) { - (void)(isutf(str[++offs]) || isutf(str[++offs]) || - isutf(str[++offs]) || ++offs); - charnum--; - } - return offs; -} - -/* byte offset => charnum */ -int u8_charnum(char *s, int offset) -{ - int charnum = 0, offs=0; - - while (offs < offset && s[offs]) { - (void)(isutf(s[++offs]) || isutf(s[++offs]) || - isutf(s[++offs]) || ++offs); - charnum++; - } - return charnum; -} - -/* number of characters */ -int u8_strlen(const char *s) -{ - int count = 0; - int i = 0; - - while (u8_nextchar(s, &i) != 0) - count++; - - return count; -} - -/* reads the next utf-8 sequence out of a string, updating an index */ -uint32_t u8_nextchar(const char *s, int *i) -{ - uint32_t ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += (unsigned char)s[(*i)++]; - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; -} - -void u8_inc(const char *s, int *i) -{ - (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || - isutf(s[++(*i)]) || ++(*i)); -} - -void u8_dec(const char *s, int *i) -{ - (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || - isutf(s[--(*i)]) || --(*i)); -} - -int octal_digit(char c) -{ - return (c >= '0' && c <= '7'); -} - -int hex_digit(char c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f')); -} - -/* assumes that src points to the character after a backslash - returns number of input characters processed */ -int u8_read_escape_sequence(char *str, uint32_t *dest) -{ - uint32_t ch; - char digs[9]="\0\0\0\0\0\0\0\0"; - int dno=0, i=1; - - ch = (uint32_t)str[0]; /* take literal character */ - if (str[0] == 'n') - ch = L'\n'; - else if (str[0] == 't') - ch = L'\t'; - else if (str[0] == 'r') - ch = L'\r'; - else if (str[0] == 'b') - ch = L'\b'; - else if (str[0] == 'f') - ch = L'\f'; - else if (str[0] == 'v') - ch = L'\v'; - else if (str[0] == 'a') - ch = L'\a'; - else if (octal_digit(str[0])) { - i = 0; - do { - digs[dno++] = str[i++]; - } while (octal_digit(str[i]) && dno < 3); - ch = strtol(digs, NULL, 8); - } - else if (str[0] == 'x') { - while (hex_digit(str[i]) && dno < 2) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'u') { - while (hex_digit(str[i]) && dno < 4) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'U') { - while (hex_digit(str[i]) && dno < 8) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - *dest = ch; - - return i; -} - -/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 - example: u8_unescape(mybuf, 256, "hello\\u220e") - note the double backslash is needed if called on a C string literal */ -int u8_unescape(char *buf, int sz, char *src) -{ - int c=0, amt; - uint32_t ch; - char temp[4]; - - while (*src && c < sz) { - if (*src == '\\') { - src++; - amt = u8_read_escape_sequence(src, &ch); - } - else { - ch = (uint32_t)*src; - amt = 1; - } - src += amt; - amt = u8_wc_toutf8(temp, ch); - if (amt > sz-c) - break; - memcpy(&buf[c], temp, amt); - c += amt; - } - if (c < sz) - buf[c] = '\0'; - return c; -} - -char *u8_strchr(char *s, uint32_t ch, int *charn) -{ - int i = 0, lasti=0; - uint32_t c; - - *charn = 0; - while (s[i]) { - c = u8_nextchar(s, &i); - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -char *u8_memchr(char *s, uint32_t ch, size_t sz, int *charn) -{ - int i = 0, lasti=0; - uint32_t c; - int csz; - - *charn = 0; - while (i < sz) { - c = csz = 0; - do { - c <<= 6; - c += (unsigned char)s[i++]; - csz++; - } while (i < sz && !isutf(s[i])); - c -= offsetsFromUTF8[csz-1]; - - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -int u8_is_locale_utf8(char *locale) -{ - /* this code based on libutf8 */ - const char* cp = locale; - - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { - if (*cp == '.') { - const char* encoding = ++cp; - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) - ; - if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) - || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) - return 1; /* it's UTF-8 */ - break; - } - } - return 0; -} +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +#include "utf8.h" + +static const uint32_t offsetsFromUTF8[6] = { + 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL +}; + +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* returns length of next utf-8 sequence */ +int u8_seqlen(char c) +{ + return trailingBytesForUTF8[(unsigned int)(unsigned char)c] + 1; +} + +/* conversions without error checking + only works for valid UTF-8, i.e. no 5- or 6-byte sequences + srcsz = source size in bytes, or -1 if 0-terminated + sz = dest size in # of wide characters + + returns # characters converted + dest will always be L'\0'-terminated, even if there isn't enough room + for all the characters. + if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. +*/ +int u8_toucs(uint32_t *dest, int sz, char *src, int srcsz) +{ + uint32_t ch; + char *src_end = src + srcsz; + int nb; + int i=0; + + while (i < sz-1) { + nb = trailingBytesForUTF8[(unsigned char)*src]; + if (srcsz == -1) { + if (*src == 0) + goto done_toucs; + } + else { + if (src + nb >= src_end) + goto done_toucs; + } + ch = 0; + switch (nb) { + /* these fall through deliberately */ + case 3: ch += (unsigned char)*src++; ch <<= 6; + case 2: ch += (unsigned char)*src++; ch <<= 6; + case 1: ch += (unsigned char)*src++; ch <<= 6; + case 0: ch += (unsigned char)*src++; + } + ch -= offsetsFromUTF8[nb]; + dest[i++] = ch; + } + done_toucs: + dest[i] = 0; + return i; +} + +/* srcsz = number of source characters, or -1 if 0-terminated + sz = size of dest buffer in bytes + + returns # characters converted + dest will only be '\0'-terminated if there is enough space. this is + for consistency; imagine there are 2 bytes of space left, but the next + character requires 3 bytes. in this case we could NUL-terminate, but in + general we can't when there's insufficient space. therefore this function + only NUL-terminates if all the characters fit, and there's space for + the NUL as well. + the destination string will never be bigger than the source string. +*/ +int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz) +{ + uint32_t ch; + int i = 0; + char *dest_end = dest + sz; + + while (srcsz<0 ? src[i]!=0 : i < srcsz) { + ch = src[i]; + if (ch < 0x80) { + if (dest >= dest_end) + return i; + *dest++ = (char)ch; + } + else if (ch < 0x800) { + if (dest >= dest_end-1) + return i; + *dest++ = (ch>>6) | 0xC0; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x10000) { + if (dest >= dest_end-2) + return i; + *dest++ = (ch>>12) | 0xE0; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x110000) { + if (dest >= dest_end-3) + return i; + *dest++ = (ch>>18) | 0xF0; + *dest++ = ((ch>>12) & 0x3F) | 0x80; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + i++; + } + if (dest < dest_end) + *dest = '\0'; + return i; +} + +int u8_wc_toutf8(char *dest, uint32_t ch) +{ + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = (ch>>6) | 0xC0; + dest[1] = (ch & 0x3F) | 0x80; + return 2; + } + if (ch < 0x10000) { + dest[0] = (ch>>12) | 0xE0; + dest[1] = ((ch>>6) & 0x3F) | 0x80; + dest[2] = (ch & 0x3F) | 0x80; + return 3; + } + if (ch < 0x110000) { + dest[0] = (ch>>18) | 0xF0; + dest[1] = ((ch>>12) & 0x3F) | 0x80; + dest[2] = ((ch>>6) & 0x3F) | 0x80; + dest[3] = (ch & 0x3F) | 0x80; + return 4; + } + return 0; +} + +/* charnum => byte offset */ +int u8_offset(char *str, int charnum) +{ + int offs=0; + + while (charnum > 0 && str[offs]) { + (void)(isutf(str[++offs]) || isutf(str[++offs]) || + isutf(str[++offs]) || ++offs); + charnum--; + } + return offs; +} + +/* byte offset => charnum */ +int u8_charnum(char *s, int offset) +{ + int charnum = 0, offs=0; + + while (offs < offset && s[offs]) { + (void)(isutf(s[++offs]) || isutf(s[++offs]) || + isutf(s[++offs]) || ++offs); + charnum++; + } + return charnum; +} + +/* number of characters */ +int u8_strlen(const char *s) +{ + int count = 0; + int i = 0; + + while (u8_nextchar(s, &i) != 0) + count++; + + return count; +} + +/* reads the next utf-8 sequence out of a string, updating an index */ +uint32_t u8_nextchar(const char *s, int *i) +{ + uint32_t ch = 0; + int sz = 0; + + do { + ch <<= 6; + ch += (unsigned char)s[(*i)++]; + sz++; + } while (s[*i] && !isutf(s[*i])); + ch -= offsetsFromUTF8[sz-1]; + + return ch; +} + +void u8_inc(const char *s, int *i) +{ + (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || + isutf(s[++(*i)]) || ++(*i)); +} + +void u8_dec(const char *s, int *i) +{ + (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || + isutf(s[--(*i)]) || --(*i)); +} + +int octal_digit(char c) +{ + return (c >= '0' && c <= '7'); +} + +int hex_digit(char c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')); +} + +/* assumes that src points to the character after a backslash + returns number of input characters processed */ +int u8_read_escape_sequence(char *str, uint32_t *dest) +{ + uint32_t ch; + char digs[9]="\0\0\0\0\0\0\0\0"; + int dno=0, i=1; + + ch = (uint32_t)str[0]; /* take literal character */ + if (str[0] == 'n') + ch = L'\n'; + else if (str[0] == 't') + ch = L'\t'; + else if (str[0] == 'r') + ch = L'\r'; + else if (str[0] == 'b') + ch = L'\b'; + else if (str[0] == 'f') + ch = L'\f'; + else if (str[0] == 'v') + ch = L'\v'; + else if (str[0] == 'a') + ch = L'\a'; + else if (octal_digit(str[0])) { + i = 0; + do { + digs[dno++] = str[i++]; + } while (octal_digit(str[i]) && dno < 3); + ch = strtol(digs, NULL, 8); + } + else if (str[0] == 'x') { + while (hex_digit(str[i]) && dno < 2) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'u') { + while (hex_digit(str[i]) && dno < 4) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'U') { + while (hex_digit(str[i]) && dno < 8) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + *dest = ch; + + return i; +} + +/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 + example: u8_unescape(mybuf, 256, "hello\\u220e") + note the double backslash is needed if called on a C string literal */ +int u8_unescape(char *buf, int sz, char *src) +{ + int c=0, amt; + uint32_t ch; + char temp[4]; + + while (*src && c < sz) { + if (*src == '\\') { + src++; + amt = u8_read_escape_sequence(src, &ch); + } + else { + ch = (uint32_t)*src; + amt = 1; + } + src += amt; + amt = u8_wc_toutf8(temp, ch); + if (amt > sz-c) + break; + memcpy(&buf[c], temp, amt); + c += amt; + } + if (c < sz) + buf[c] = '\0'; + return c; +} + +char *u8_strchr(char *s, uint32_t ch, int *charn) +{ + int i = 0, lasti=0; + uint32_t c; + + *charn = 0; + while (s[i]) { + c = u8_nextchar(s, &i); + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +char *u8_memchr(char *s, uint32_t ch, size_t sz, int *charn) +{ + int i = 0, lasti=0; + uint32_t c; + int csz; + + *charn = 0; + while (i < sz) { + c = csz = 0; + do { + c <<= 6; + c += (unsigned char)s[i++]; + csz++; + } while (i < sz && !isutf(s[i])); + c -= offsetsFromUTF8[csz-1]; + + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +int u8_is_locale_utf8(char *locale) +{ + /* this code based on libutf8 */ + const char* cp = locale; + + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { + if (*cp == '.') { + const char* encoding = ++cp; + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) + ; + if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) + || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) + return 1; /* it's UTF-8 */ + break; + } + } + return 0; +} diff --git a/src/utf8.h b/src/utf8.h index 94003b8..40f8be2 100644 --- a/src/utf8.h +++ b/src/utf8.h @@ -1,57 +1,57 @@ -#include - -/* is c the start of a utf8 sequence? */ -#define isutf(c) (((c)&0xC0)!=0x80) - -/* convert UTF-8 data to wide character */ -int u8_toucs(uint32_t *dest, int sz, char *src, int srcsz); - -/* the opposite conversion */ -int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz); - -/* single character to UTF-8 */ -int u8_wc_toutf8(char *dest, uint32_t ch); - -/* character number to byte offset */ -int u8_offset(char *str, int charnum); - -/* byte offset to character number */ -int u8_charnum(char *s, int offset); - -/* return next character, updating an index variable */ -uint32_t u8_nextchar(const char *s, int *i); - -/* move to next character */ -void u8_inc(const char *s, int *i); - -/* move to previous character */ -void u8_dec(const char *s, int *i); - -/* returns length of next utf-8 sequence */ -int u8_seqlen(char c); - -/* assuming src points to the character after a backslash, read an - escape sequence, storing the result in dest and returning the number of - input characters processed */ -int u8_read_escape_sequence(char *src, uint32_t *dest); - -/* convert a string "src" containing escape sequences to UTF-8 */ -int u8_unescape(char *buf, int sz, char *src); - -/* utility predicates used by the above */ -int octal_digit(char c); -int hex_digit(char c); - -/* return a pointer to the first occurrence of ch in s, or NULL if not - found. character index of found character returned in *charn. */ -char *u8_strchr(char *s, uint32_t ch, int *charn); - -/* same as the above, but searches a buffer of a given size instead of - a NUL-terminated string. */ -char *u8_memchr(char *s, uint32_t ch, size_t sz, int *charn); - -/* count the number of characters in a UTF-8 string */ -int u8_strlen(const char *s); - -int u8_is_locale_utf8(char *locale); - +#include + +/* is c the start of a utf8 sequence? */ +#define isutf(c) (((c)&0xC0)!=0x80) + +/* convert UTF-8 data to wide character */ +int u8_toucs(uint32_t *dest, int sz, char *src, int srcsz); + +/* the opposite conversion */ +int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz); + +/* single character to UTF-8 */ +int u8_wc_toutf8(char *dest, uint32_t ch); + +/* character number to byte offset */ +int u8_offset(char *str, int charnum); + +/* byte offset to character number */ +int u8_charnum(char *s, int offset); + +/* return next character, updating an index variable */ +uint32_t u8_nextchar(const char *s, int *i); + +/* move to next character */ +void u8_inc(const char *s, int *i); + +/* move to previous character */ +void u8_dec(const char *s, int *i); + +/* returns length of next utf-8 sequence */ +int u8_seqlen(char c); + +/* assuming src points to the character after a backslash, read an + escape sequence, storing the result in dest and returning the number of + input characters processed */ +int u8_read_escape_sequence(char *src, uint32_t *dest); + +/* convert a string "src" containing escape sequences to UTF-8 */ +int u8_unescape(char *buf, int sz, char *src); + +/* utility predicates used by the above */ +int octal_digit(char c); +int hex_digit(char c); + +/* return a pointer to the first occurrence of ch in s, or NULL if not + found. character index of found character returned in *charn. */ +char *u8_strchr(char *s, uint32_t ch, int *charn); + +/* same as the above, but searches a buffer of a given size instead of + a NUL-terminated string. */ +char *u8_memchr(char *s, uint32_t ch, size_t sz, int *charn); + +/* count the number of characters in a UTF-8 string */ +int u8_strlen(const char *s); + +int u8_is_locale_utf8(char *locale); +