From 75580a01ae2cff2c3de773d643dbc1a11af76fb5 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 10:43:52 +0300 Subject: [PATCH] changelog stuff - make changelog visible in-game - fix issues with the changelog in ModInfoPopup & scrollbar --- .gitignore | 1 + CHANGELOG.md | 181 ++++++++++--------- CMakeLists.txt | 1 + loader/CMakeLists.txt | 1 + loader/src/internal/about.hpp.in | 1 + loader/src/loader/ModImpl.cpp | 1 + loader/src/ui/internal/info/ModInfoPopup.cpp | 26 ++- loader/src/ui/internal/info/ModInfoPopup.hpp | 2 +- loader/src/ui/nodes/Scrollbar.cpp | 4 + 9 files changed, 120 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index 78fb94ee..e54eeeac 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ loader/src/internal/about.hpp loader/src/internal/resources.hpp loader/resources/mod.json loader/resources/blanks/rename.js +loader/resources/changelog.md fods-catgirl-hideout.txt # krita files too because alk is funny diff --git a/CHANGELOG.md b/CHANGELOG.md index dca7bb73..f0b86c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,124 +1,125 @@ # Geode Changelog ## v1.0.0-beta.12 - * Fix crash when installing mods (2efe772) - * FMOD is now linked on MacOS (f662251) - * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work (ab2abcd) + * Fix crash when installing mods + * FMOD is now linked on MacOS + * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work + * Make Geode changelog visible in-game ## v1.0.0-beta.11 - * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro (5af15fb) - * Add `CCNode::removeChildByID` (5f3c658) - * Add `CCNode::hasAncestor` (38575ac) - * Add `CCScene::get` and `CCScheduler::get` (38575ac) - * Add `geode::cocos::getMousePos` (306fde7) - * Add `GEODE_DONT_INSTALL_MODS` option to CMake (7ca9959) - * Add logging `std::vector` with `log::` functions (7305445) - * Add `EventListener::getFilter` (5cdfbc3) - * Add `AttributeSetEvent` for detecting when attributes are added to nodes (69bd0d9) - * Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes (35f7f86) - * Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial) (e92541a, 0e46362) - * Add option to ignore invisible children to `Layout` (152f90c) - * `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability (7963469) - * Implement file picker on Mac (d7b0e09) - * Define `CCNode::retainCount` inline (57947a9, 72448e1) - * `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes (81472c9) - * Update TulipHook version (3d339ef) - * Make sure mod load/enable/etc. events are only ever posted in the GD thread (93fd396) - * `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1) (22a6745) - * Give a name to `ccTouchType` (e2e1da0) - * Fix `Scrollbar` being funky sometimes (585a9de, 83b0850) - * Fix mod resources not being loaded if the mod is enabled at runtime (9fb5051) - * Fix `EditLevelLayer` description update button ID & layout (21ee689) - * Fix hooking functions with unpredictable calling conventions (94138f3, 33a2883) - * Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled (4318a8d) - * Fix code editors showing a ton of warnings with `$modify` (cf1371f) - * Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite` (0a37b01, eabb68b) - * Fix `Mod::enableHook` error message (162979c) + * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro + * Add `CCNode::removeChildByID` + * Add `CCNode::hasAncestor` + * Add `CCScene::get` and `CCScheduler::get` + * Add `geode::cocos::getMousePos` + * Add `GEODE_DONT_INSTALL_MODS` option to CMake + * Add logging `std::vector` with `log::` functions + * Add `EventListener::getFilter` + * Add `AttributeSetEvent` for detecting when attributes are added to nodes + * Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes + * Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial) + * Add option to ignore invisible children to `Layout` + * `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability + * Implement file picker on Mac + * Define `CCNode::retainCount` inline + * `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes + * Update TulipHook version + * Make sure mod load/enable/etc. events are only ever posted in the GD thread + * `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1) + * Give a name to `ccTouchType` + * Fix `Scrollbar` being funky sometimes + * Fix mod resources not being loaded if the mod is enabled at runtime + * Fix `EditLevelLayer` description update button ID & layout + * Fix hooking functions with unpredictable calling conventions + * Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled + * Fix code editors showing a ton of warnings with `$modify` + * Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite` + * Fix `Mod::enableHook` error message * Lots of bindings on both Windows & Mac (50+ commits related to bindings) ## v1.0.0-beta.10 - * Fix loader minimum mod version preventing the loader itself from loading (ebfa7b2) - * Fix recursive comparison in VersionTag (1b2c760) - * `geode/unzipped` is now deleted on startup if it exists (eb0e4b6) + * Fix loader minimum mod version preventing the loader itself from loading + * Fix recursive comparison in VersionTag + * `geode/unzipped` is now deleted on startup if it exists ## v1.0.0-beta.9 - * Fix multiple modifiers not being able to have fields on same class due to having same field index (7710fa9) - * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` (4a15afc) + * Fix multiple modifiers not being able to have fields on same class due to having same field index + * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` ## v1.0.0-beta.8 - * Unload the mod even when first time warning pops up (63b4774) - * Error when address of a function returns nullptr when hooking (724a9d3) - * Add support for Geode CLI v2.0.0 (which has not been released yet) (088ac7b, deadb58) - * Logging no longer causes a crash on invalid formats, but instead just warns (6aba7cf) - * `file::pickFile` now uses the last item in the default path as the default filename to save/open (5c9ee08) - * Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr` (33a91d6) + * Unload the mod even when first time warning pops up + * Error when address of a function returns nullptr when hooking + * Add support for Geode CLI v2.0.0 (which has not been released yet) + * Logging no longer causes a crash on invalid formats, but instead just warns + * `file::pickFile` now uses the last item in the default path as the default filename to save/open + * Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr` ## v1.0.0-beta.7 - * Add `Mod::getResourcesDir` for getting the mod resources directory (0055032) - * Deprecate `file::listFiles` for `file::readDirectory` (9f60091) - * Fix getting virtual function addresses for CCFileUtils (c183a35) - * Rename `BasedButtonSprite` sprite names to be more expressive (4d2daec) - * Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS (d024dbb) - * Fix settings not getting broadcasted (7089194) - * Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled (3222097) - * Display Geode commit hash in the bottom right of the mod info layer (1dfa907) - * Fix `EditorPauseLayer` info labels on the top left being too big (f5983a2) + * Add `Mod::getResourcesDir` for getting the mod resources directory + * Deprecate `file::listFiles` for `file::readDirectory` + * Fix getting virtual function addresses for CCFileUtils + * Rename `BasedButtonSprite` sprite names to be more expressive + * Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS + * Fix settings not getting broadcasted + * Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled + * Display Geode commit hash in the bottom right of the mod info layer + * Fix `EditorPauseLayer` info labels on the top left being too big ## v1.0.0-beta.6 * Reworked layouts from the ground up - see [the docs page](https://docs.geode-sdk.org/tutorials/layouts) for more information about how the new system works (#137) * Update the IDs for a bunch of layers, aswell as adding some predefined layouts (3f64b98, ef9e741, a78bc0c, cb1a6f1, ea037a9, f7ddf0a, ...) - * Add IDs & layouts to `EditorPauseLayer` (12d88ae) - * Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones (eb10eca, 4613af6) + * Add IDs & layouts to `EditorPauseLayer` + * Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones * Add `CCSize::aspect` convenience method - * Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed) (0055032) - * Add `Mod::addCustomSetting` for convenience in registering custom settings (7089194) - * Add `file::readDirectory` as a sanely named alternative to `file::listFiles` (9f60091) - * Move `GEODE_DLL` to the structs themselves in `JsonValidation` (06bc6fd) - * Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions (bbbf332) - * `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled (3222097) - * Geode's internal mod representation is now included in the loader's loaded mods list (4261e99) - * Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor (7089194) - * Fix some warnings (9c9706b, f7bfa21) - * Fix `CCNode::swapChildIndices` (ba0851e) - * Fix `typeinfo_cast` causing a crash if passed a `nullptr` (f4a3258) - * Fix `ranges::reverse` causing UB (ffd50eb) - * Other fixes & improvements (cb00c21) + * Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed) + * Add `Mod::addCustomSetting` for convenience in registering custom settings + * Add `file::readDirectory` as a sanely named alternative to `file::listFiles` + * Move `GEODE_DLL` to the structs themselves in `JsonValidation` + * Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions + * `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled + * Geode's internal mod representation is now included in the loader's loaded mods list + * Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor + * Fix some warnings + * Fix `CCNode::swapChildIndices` + * Fix `typeinfo_cast` causing a crash if passed a `nullptr` + * Fix `ranges::reverse` causing UB + * Other fixes & improvements ## v1.0.0-beta.5 -- Make ModInfo Pimpl 51990ad89b25cecbabaf748a5bcb279227fce090 -- Fix crash with event listeners 1f7d50a9b9140d02f6a9afb97734eb9761b6a0d4 -- Some bindings 4a9f6ba52a3d756d9bc28c1809afc92479783673 -- Make mods binaries not silently fail to load 0eb5f01ca81435cb90f2bc9d8d97a86405dadd1c -- Assume dependency version is >= comparison by default 41aef57758d7b858d5fa7cb22ab1ffe603ff365f -- Fix not following thunks 65f2cbb286cc1e5af57e43451862a2233d66453e +- Make ModInfo Pimpl +- Fix crash with event listeners +- Some bindings +- Make mods binaries not silently fail to load +- Assume dependency version is >= comparison by default +- Fix not following thunks ## v1.0.0-beta.4 - Add some bindings - Fix macOS libzstd crash ## v1.0.0-beta.3 - - Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `Result::except` now works with non-copyable types (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `Zip` and `Unzip` now support in-memory ZIP extraction and creation (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `ComparableVersionInfo::compare` now always returns false if the major versions are different (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`) (6d3847d9e13fdf69cea0b9a69376ebcd88e71725) - - Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked (ab0030136ab8c20731fe768ef5f3b16ae4245583) - - `CC_DLL` no longer expands to dllexport/dllimport (ab0030136ab8c20731fe768ef5f3b16ae4245583) - - The JSON lib now default constructs to object, hopefully fixing uncaught bugs (30101fc0b5112317aac3c9eeea0aab888ca8b30d) - - Something related to codegen and addresser? I have no clue what it does, so you probably won't have either (ae1eb8bb7162342f598e047a459e3808801f731a, 1e9faac5aa5a32b0cb5e6ffaac0c5cbfc217e9cb, fea049cca069a08181ab66cacda6f2417c006a2f, ad261846919e503cc3faf75d777ab2f2882bc6bb, ...) - - MacOS minimum version bumped to 10.14 (916f54063008c6bdf892d02f8bcd92b58606817e) + - Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more + - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future + - `Result::except` now works with non-copyable types + - `Zip` and `Unzip` now support in-memory ZIP extraction and creation + - `ComparableVersionInfo::compare` now always returns false if the major versions are different + - `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`) + - Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked + - `CC_DLL` no longer expands to dllexport/dllimport + - The JSON lib now default constructs to object, hopefully fixing uncaught bugs + - Something related to codegen and addresser? I have no clue what it does, so you probably won't have either + - MacOS minimum version bumped to 10.14 ## v1.0.0-beta.2 - * Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value (5bbd34c) - * Fixed bug where loading would crash if one of the mods' binaries failed to load (ef86ae0) + * Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value + * Fixed bug where loading would crash if one of the mods' binaries failed to load ## v1.0.0-beta.1 - * Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. (deab672) - * Fix resources not being downloaded automatically by using a fallback to latest release (a418828) - * Add a new clear instruction popup in case downloading still fails (30dc9ad) - * String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!) (b6a6e4d) - * Various internal bugfixes & improvements (ceb02e9, a90b3e1, b00ab40, c644b43) + * Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. + * Fix resources not being downloaded automatically by using a fallback to latest release + * Add a new clear instruction popup in case downloading still fails + * String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!) + * Various internal bugfixes & improvements ## v1.0.0-alpha diff --git a/CMakeLists.txt b/CMakeLists.txt index f2963fe5..28afb440 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ target_compile_definitions(${PROJECT_NAME} INTERFACE -DPROJECT_NAME=${CMAKE_PROJ set(GEODE_CODEGEN_PATH ${CMAKE_CURRENT_BINARY_DIR}/codegenned) set(GEODE_BIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) set(GEODE_LOADER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/loader) +set(GEODE_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) include(cmake/GeodeFile.cmake) include(cmake/Platform.cmake) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index f19f0a20..e079e4d8 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -30,6 +30,7 @@ execute_process( configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json) file(READ resources/mod.json LOADER_MOD_JSON) file(READ resources/about.md LOADER_ABOUT_MD) +file(READ ${GEODE_ROOT_PATH}/CHANGELOG.md LOADER_CHANGELOG_MD) configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp) # Source files diff --git a/loader/src/internal/about.hpp.in b/loader/src/internal/about.hpp.in index 6f15b842..40dbf1b5 100644 --- a/loader/src/internal/about.hpp.in +++ b/loader/src/internal/about.hpp.in @@ -3,6 +3,7 @@ #include static constexpr const char* LOADER_ABOUT_MD = R"MD_SEPARATOR(@LOADER_ABOUT_MD@)MD_SEPARATOR"; +static constexpr const char* LOADER_CHANGELOG_MD = R"MD_SEPARATOR(@LOADER_CHANGELOG_MD@)MD_SEPARATOR"; static constexpr const char* LOADER_VERSION_STR = "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@"; static constexpr int LOADER_VERSION_MAJOR = @PROJECT_VERSION_MAJOR@; static constexpr int LOADER_VERSION_MINOR = @PROJECT_VERSION_MINOR@; diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index fe33adf2..41ca17cc 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -694,6 +694,7 @@ static ModInfo getModImplInfo() { } auto info = infoRes.unwrap(); info.details() = LOADER_ABOUT_MD; + info.changelog() = LOADER_CHANGELOG_MD; info.supportInfo() = SUPPORT_INFO; info.supportsDisabling() = false; return info; diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index a1d5d861..6b1d79f0 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -112,12 +112,8 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { // changelog if (info.changelog()) { - m_changelogArea = MDTextArea::create(info.changelog().value(), { 350.f, 137.5f }); - m_changelogArea->setPosition( - -5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f - ); - m_changelogArea->setVisible(false); - m_mainLayer->addChild(m_changelogArea); + // m_changelogArea is only created if the changelog button is clicked + // because changelogs can get really long and take a while to load auto changelogBtnOffSpr = ButtonSprite::create( CCSprite::createWithSpriteFrameName("changelog.png"_spr), @@ -225,9 +221,19 @@ void ModInfoPopup::onInfo(CCObject*) { } void ModInfoPopup::onChangelog(CCObject* sender) { - auto toggle = static_cast(sender); auto winSize = CCDirector::get()->getWinSize(); + if (!m_changelogArea) { + m_changelogArea = MDTextArea::create(Mod::get()->getModInfo().changelog().value(), { 350.f, 137.5f }); + m_changelogArea->setPosition( + -5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f + ); + m_changelogArea->setVisible(false); + m_mainLayer->addChild(m_changelogArea); + } + + auto toggle = static_cast(sender); + m_detailsArea->setVisible(toggle->isToggled()); // as it turns out, cocos2d is stupid and still passes touch // events to invisible nodes @@ -243,6 +249,12 @@ void ModInfoPopup::onChangelog(CCObject* sender) { !toggle->isToggled() ? winSize.width / 2 - m_changelogArea->getScaledContentSize().width / 2 : -5000.f ); + + m_scrollbar->setTarget( + toggle->isToggled() ? + m_detailsArea->getScrollLayer() : + m_changelogArea->getScrollLayer() + ); } void ModInfoPopup::keyDown(enumKeyCodes key) { diff --git a/loader/src/ui/internal/info/ModInfoPopup.hpp b/loader/src/ui/internal/info/ModInfoPopup.hpp index 9a6ac92f..aed289ed 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.hpp +++ b/loader/src/ui/internal/info/ModInfoPopup.hpp @@ -35,7 +35,7 @@ protected: CCMenuItemSpriteExtra* m_infoBtn; CCLabelBMFont* m_updateVersionLabel = nullptr; MDTextArea* m_detailsArea; - MDTextArea* m_changelogArea; + MDTextArea* m_changelogArea = nullptr; Scrollbar* m_scrollbar; void onChangelog(CCObject*); diff --git a/loader/src/ui/nodes/Scrollbar.cpp b/loader/src/ui/nodes/Scrollbar.cpp index a3731919..406fe80c 100644 --- a/loader/src/ui/nodes/Scrollbar.cpp +++ b/loader/src/ui/nodes/Scrollbar.cpp @@ -99,6 +99,10 @@ void Scrollbar::draw() { auto y = m_target->m_contentLayer->getPositionY(); auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0; + if (thumbHeight < 15.f) { + thumbHeight = 15.f; + } + auto thumbPosY = -targetHeight / 2 + thumbHeight / 4 - 5.0f + (h ? (-y) / h : 1.f) * (targetHeight - thumbHeight / 2 + 10.0f);