2025-12-20 16:38:51 +03:00
# include "BookmarkManager.hpp"
# include "../World.hpp"
# include "../MainProgram.hpp"
2025-12-23 17:17:33 +03:00
# include "BookmarkListItem.hpp"
2025-12-21 00:33:04 +03:00
# include "Helpers/NetworkingObjects/NetObjOrderedList.hpp"
# include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp"
2026-01-02 09:22:52 +03:00
# include <cereal/types/unordered_map.hpp>
2025-12-20 16:38:51 +03:00
BookmarkManager : : BookmarkManager ( World & w ) :
world ( w )
{ }
2026-01-01 22:46:02 +03:00
void BookmarkManager : : server_init_no_file ( ) {
bookmarkListRoot = world . netObjMan . make_obj_from_ptr < BookmarkListItem > ( new BookmarkListItem ( world . netObjMan , " ROOT " , true , { } ) ) ;
2025-12-23 17:17:33 +03:00
}
void BookmarkManager : : refresh_gui_data ( ) {
selectionData = GUIStuff : : TreeListing : : SelectionData ( ) ;
2026-01-03 13:35:24 +03:00
editing_bookmark_check ( ) ;
2025-12-23 17:17:33 +03:00
nameToEdit . clear ( ) ;
nameForNew . clear ( ) ;
2025-12-20 16:38:51 +03:00
}
2025-12-21 00:33:04 +03:00
void BookmarkManager : : setup_list_gui ( const std : : string & id ) {
using namespace NetworkingObjects ;
if ( bookmarkListRoot ) {
auto & gui = world . main . toolbar . gui ;
2025-12-23 17:17:33 +03:00
gui . push_id ( id ) ;
2025-12-24 12:42:27 +03:00
if ( bookmarkListRoot - > get_folder_list ( ) - > empty ( ) ) {
gui . text_label_centered ( " No bookmarks yet... " ) ;
selectionData = GUIStuff : : TreeListing : : SelectionData ( ) ;
oldSelection . clear ( ) ;
nameToEdit . clear ( ) ;
}
else {
std : : optional < NetObjID > toDeleteParent ;
std : : optional < NetObjID > toDeleteObject ;
gui . tree_listing ( " list " , bookmarkListRoot . get_net_id ( ) , GUIStuff : : TreeListing : : DisplayData {
. getObjInListAtIndex = [ & ] ( NetObjID parentId , size_t index ) - > std : : optional < GUIStuff : : TreeListing : : DisplayData : : ObjInList > {
NetObjOrderedList < BookmarkListItem > & bookmarkParentFolder = * world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( parentId ) - > get_folder_list ( ) ;
if ( bookmarkParentFolder . size ( ) < = index )
return std : : nullopt ;
2025-12-30 19:46:08 +03:00
auto itemAtIndex = bookmarkParentFolder . at ( index ) ;
2025-12-24 12:42:27 +03:00
return GUIStuff : : TreeListing : : DisplayData : : ObjInList {
2025-12-30 19:46:08 +03:00
. id = itemAtIndex - > obj . get_net_id ( ) ,
. isDirectory = itemAtIndex - > obj - > is_folder ( ) ,
. isDirectoryOpen = itemAtIndex - > obj - > is_folder ( ) ? itemAtIndex - > obj - > is_folder_open ( ) : false
2025-12-24 12:42:27 +03:00
} ;
} ,
. getIndexOfObjInList = [ & ] ( const GUIStuff : : TreeListing : : ParentObjectIDPair & idPair ) {
return world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( idPair . parent ) - > get_folder_list ( ) - > get ( idPair . object ) - > pos ;
} ,
. setDirectoryOpen = [ & ] ( NetObjID netID , bool newDirectoryOpen ) {
world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( netID ) - > set_folder_open ( newDirectoryOpen ) ;
} ,
. drawNonDirectoryObjIconGUI = [ & ] ( NetObjID netID ) {
CLAY_AUTO_ID ( {
. layout = {
. sizing = { . width = CLAY_SIZING_GROW ( 0 ) , . height = CLAY_SIZING_GROW ( 0 ) } ,
. padding = CLAY_PADDING_ALL ( 2 ) ,
} ,
} ) {
gui . svg_icon ( " bookmark ico " , " data/icons/bookmark.svg " ) ;
2025-12-23 14:10:33 +03:00
}
2025-12-24 12:42:27 +03:00
return false ;
} ,
. drawObjGUI = [ & ] ( const GUIStuff : : TreeListing : : ParentObjectIDPair & idPair ) {
auto tempPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( idPair . object ) ;
2025-12-25 17:18:28 +03:00
bool isButtonClicked = false ;
2025-12-24 12:42:27 +03:00
if ( Clay_Hovered ( ) & & gui . io - > mouse . leftClick > = 2 & & ! tempPtr - > is_folder ( ) & & selectionData . objsSelected . contains ( idPair . object ) & & ! gui . io - > key . leftCtrl & & ! gui . io - > key . leftShift )
tempPtr - > get_bookmark_data ( ) . jump_to ( world ) ;
CLAY_AUTO_ID ( {
. layout = {
. sizing = { . width = CLAY_SIZING_GROW ( 0 ) , . height = CLAY_SIZING_GROW ( 0 ) } ,
. childAlignment = { . x = CLAY_ALIGN_X_LEFT , . y = CLAY_ALIGN_Y_CENTER }
} ,
} ) {
gui . text_label ( tempPtr - > get_name ( ) ) ;
2025-12-23 14:10:33 +03:00
}
2025-12-24 12:42:27 +03:00
if ( ! tempPtr - > is_folder ( ) & & gui . svg_icon_button_transparent ( " jump button " , " data/icons/jump.svg " , false , GUIStuff : : TreeListing : : ENTRY_HEIGHT ) ) {
tempPtr - > get_bookmark_data ( ) . jump_to ( world ) ;
2025-12-25 17:18:28 +03:00
isButtonClicked = true ;
2025-12-23 14:10:33 +03:00
}
2025-12-24 12:42:27 +03:00
if ( gui . svg_icon_button_transparent ( " delete button " , " data/icons/trash.svg " , false , GUIStuff : : TreeListing : : ENTRY_HEIGHT ) ) {
toDeleteParent = idPair . parent ;
toDeleteObject = idPair . object ;
2025-12-25 17:18:28 +03:00
isButtonClicked = true ;
2025-12-24 12:42:27 +03:00
}
2025-12-25 17:18:28 +03:00
return isButtonClicked ;
2025-12-24 12:42:27 +03:00
} ,
. moveObjectsToListAtIndex = [ & ] ( NetObjID listObj , size_t index , const std : : vector < GUIStuff : : TreeListing : : ParentObjectIDPair > & objsToInsert ) {
2026-01-03 19:05:00 +03:00
std : : unordered_map < WorldUndoManager : : UndoObjectID , std : : pair < std : : vector < uint32_t > , std : : vector < WorldUndoManager : : UndoObjectID > > > toEraseMapUndo ;
WorldUndoManager : : UndoObjectID insertParentUndoID ;
uint32_t insertUndoPosition ;
std : : vector < WorldUndoManager : : UndoObjectID > insertedUndoIDs ;
2025-12-24 12:42:27 +03:00
world . netObjMan . send_multi_update_messsage ( [ & ] ( ) {
2025-12-30 19:46:08 +03:00
std : : unordered_map < NetObjID , std : : vector < NetObjOrderedListIterator < BookmarkListItem > > > toEraseMap ;
2025-12-24 12:42:27 +03:00
uint32_t newIndex = index ;
std : : vector < NetObjOwnerPtr < BookmarkListItem > > toInsertObjPtrs ;
auto & listPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( listObj ) - > get_folder_list ( ) ;
2025-12-23 17:17:33 +03:00
2026-01-03 19:05:00 +03:00
// Map parent folders to list of objects that should be erased from them
2025-12-24 12:42:27 +03:00
for ( size_t i = 0 ; i < objsToInsert . size ( ) ; i + + ) {
2025-12-30 19:46:08 +03:00
auto & parentListPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( objsToInsert [ i ] . parent ) - > get_folder_list ( ) ;
toEraseMap [ objsToInsert [ i ] . parent ] . emplace_back ( parentListPtr - > get ( objsToInsert [ i ] . object ) ) ;
2025-12-24 12:42:27 +03:00
if ( newIndex ! = 0 & & objsToInsert [ i ] . parent = = listObj & & listPtr - > get ( objsToInsert [ i ] . object ) - > pos < = index )
newIndex - - ;
}
2026-01-03 19:05:00 +03:00
// Prepare erase map for undo
for ( auto & [ parentNetID , objsToEraseList ] : toEraseMap ) {
auto & undoEraseListPairForParent = toEraseMapUndo [ world . undo . get_undoid_from_netid ( parentNetID ) ] ;
uint32_t i = 0 ;
for ( auto & objToErase : objsToEraseList ) {
undoEraseListPairForParent . first . emplace_back ( objToErase - > pos - i ) ;
undoEraseListPairForParent . second . emplace_back ( world . undo . get_undoid_from_netid ( objToErase - > obj . get_net_id ( ) ) ) ;
i + + ;
}
}
// Erase the list of objects we previously mapped to each parent, and move the erased objects to vector toInsertObjPtrs
2025-12-24 12:42:27 +03:00
for ( auto & [ listToEraseFrom , setToErase ] : toEraseMap ) {
auto & listToEraseFromPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( listToEraseFrom ) - > get_folder_list ( ) ;
2025-12-30 19:46:08 +03:00
listToEraseFromPtr - > erase_list ( listToEraseFromPtr , setToErase , & toInsertObjPtrs ) ;
2025-12-24 12:42:27 +03:00
}
2026-01-03 19:05:00 +03:00
// Insert objects in toInsertObjPtrs into the folder we have selected
2025-12-30 19:46:08 +03:00
std : : vector < std : : pair < NetObjOrderedListIterator < BookmarkListItem > , NetObjOwnerPtr < BookmarkListItem > > > toInsert ;
auto insertIt = listPtr - > at ( newIndex ) ;
2025-12-24 12:42:27 +03:00
for ( uint32_t i = 0 ; i < objsToInsert . size ( ) ; i + + ) {
auto it = std : : find_if ( toInsertObjPtrs . begin ( ) , toInsertObjPtrs . end ( ) , [ id = objsToInsert [ i ] . object ] ( NetObjOwnerPtr < BookmarkListItem > & objPtr ) {
return objPtr . get_net_id ( ) = = id ;
} ) ;
2025-12-30 19:46:08 +03:00
toInsert . emplace_back ( insertIt , std : : move ( * it ) ) ;
2025-12-24 12:42:27 +03:00
toInsert . back ( ) . second . reassign_ids ( ) ;
}
2026-01-03 19:05:00 +03:00
std : : vector < NetObjOrderedListIterator < BookmarkListItem > > insertedIterators = listPtr - > insert_ordered_list_and_send_create ( listPtr , toInsert ) ;
// Prepare insert list for undo
insertParentUndoID = world . undo . get_undoid_from_netid ( listObj ) ;
insertUndoPosition = newIndex ;
for ( auto & it : insertedIterators )
insertedUndoIDs . emplace_back ( world . undo . get_undoid_from_netid ( it - > obj . get_net_id ( ) ) ) ;
2025-12-24 12:42:27 +03:00
} , NetObjManager : : SendUpdateType : : SEND_TO_ALL , nullptr ) ;
2026-01-03 19:05:00 +03:00
class MoveBookmarksWorldUndoAction : public WorldUndoAction {
public :
// If the undo ID maps to the net id, we can also assume that the object is definitely inside the list we want to move it from, and not inside some other list
// If it was moved to another list, there would be an undo move that would move it back to this list, and if it was moved by another player the undo id wouldnt map back to the net id, and the undo would fail
// We can also assume all objects in all lists remain in the same order for the same reason, so no need to sort anything if it was sorted when the undo action was generated
MoveBookmarksWorldUndoAction ( const std : : unordered_map < WorldUndoManager : : UndoObjectID , std : : pair < std : : vector < uint32_t > , std : : vector < WorldUndoManager : : UndoObjectID > > > & initUndoEraseMap ,
WorldUndoManager : : UndoObjectID initInsertParentUndoID ,
uint32_t initInsertPosition ,
std : : vector < WorldUndoManager : : UndoObjectID > initInsertedUndoIDs ) :
undoEraseMap ( initUndoEraseMap ) ,
insertParentUndoID ( initInsertParentUndoID ) ,
insertPosition ( initInsertPosition ) ,
insertedUndoIDs ( initInsertedUndoIDs )
{ }
std : : string get_name ( ) const override {
return " Move Bookmarks " ;
}
bool undo ( WorldUndoManager & undoMan ) override {
std : : vector < NetObjOwnerPtr < BookmarkListItem > > toMoveObjs ;
std : : vector < NetObjOrderedListIterator < BookmarkListItem > > toEraseList ;
NetObjTemporaryPtr < NetObjOrderedList < BookmarkListItem > > eraseListPtr ;
std : : unordered_map < NetObjID , std : : pair < std : : vector < uint32_t > * , std : : vector < NetObjID > > > toInsertToMap ;
{
std : : optional < NetObjID > eraseListNetID = undoMan . get_netid_from_undoid ( insertParentUndoID ) ;
if ( ! eraseListNetID . has_value ( ) )
return false ;
eraseListPtr = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( eraseListNetID . value ( ) ) - > get_folder_list ( ) ;
}
{
std : : vector < NetObjID > toEraseNetIDList ;
if ( ! undoMan . fill_netid_list_from_undoid_list ( toEraseNetIDList , insertedUndoIDs ) )
return false ;
toEraseList = eraseListPtr - > get_list ( toEraseNetIDList ) ;
}
{
for ( auto & [ undoID , indexUndoIdListPair ] : undoEraseMap ) {
std : : optional < NetObjID > netID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( ! netID . has_value ( ) )
return false ;
auto & insertMapEntry = toInsertToMap [ netID . value ( ) ] ;
insertMapEntry . first = & indexUndoIdListPair . first ;
if ( ! undoMan . fill_netid_list_from_undoid_list ( insertMapEntry . second , indexUndoIdListPair . second ) )
return false ;
}
}
undoMan . world . netObjMan . send_multi_update_messsage ( [ & ] ( ) {
eraseListPtr - > erase_list ( eraseListPtr , toEraseList , & toMoveObjs ) ;
for ( auto & [ parentNetID , indexNetIDListPair ] : toInsertToMap ) {
auto & parentListPtr = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( parentNetID ) - > get_folder_list ( ) ;
std : : vector < NetObjOrderedListIterator < BookmarkListItem > > insertIteratorList = parentListPtr - > at_ordered_indices ( * indexNetIDListPair . first ) ;
auto & insertNetIDList = indexNetIDListPair . second ;
std : : vector < std : : pair < NetObjOrderedListIterator < BookmarkListItem > , NetObjOwnerPtr < BookmarkListItem > > > toInsert ;
for ( auto [ insertIt , netID ] : std : : views : : zip ( insertIteratorList , insertNetIDList ) ) {
auto it = std : : find_if ( toMoveObjs . begin ( ) , toMoveObjs . end ( ) , [ id = netID ] ( NetObjOwnerPtr < BookmarkListItem > & objPtr ) {
return objPtr . get_net_id ( ) = = id ;
} ) ;
toInsert . emplace_back ( insertIt , std : : move ( * it ) ) ;
toInsert . back ( ) . second . reassign_ids ( ) ;
}
parentListPtr - > insert_ordered_list_and_send_create ( parentListPtr , toInsert ) ;
}
} , NetObjManager : : SendUpdateType : : SEND_TO_ALL , nullptr ) ;
return true ;
}
bool redo ( WorldUndoManager & undoMan ) override {
return false ;
}
~ MoveBookmarksWorldUndoAction ( ) { }
std : : unordered_map < WorldUndoManager : : UndoObjectID , std : : pair < std : : vector < uint32_t > , std : : vector < WorldUndoManager : : UndoObjectID > > > undoEraseMap ;
WorldUndoManager : : UndoObjectID insertParentUndoID ;
uint32_t insertPosition ;
std : : vector < WorldUndoManager : : UndoObjectID > insertedUndoIDs ;
} ;
world . undo . push ( std : : make_unique < MoveBookmarksWorldUndoAction > ( toEraseMapUndo , insertParentUndoID , insertUndoPosition , insertedUndoIDs ) ) ;
2025-12-24 12:42:27 +03:00
}
} , selectionData ) ;
if ( selectionData . objsSelected ! = oldSelection ) {
2026-01-03 13:35:24 +03:00
editing_bookmark_check ( ) ;
2025-12-24 12:42:27 +03:00
if ( selectionData . objsSelected . size ( ) = = 1 ) {
NetObjTemporaryPtr < BookmarkListItem > tempPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( * selectionData . objsSelected . begin ( ) ) ;
if ( tempPtr )
nameToEdit = tempPtr - > get_name ( ) ;
2026-01-03 13:35:24 +03:00
else
2025-12-24 12:42:27 +03:00
nameToEdit . clear ( ) ;
2025-12-23 17:17:33 +03:00
}
2025-12-24 12:42:27 +03:00
else
nameToEdit . clear ( ) ;
2025-12-23 17:17:33 +03:00
}
2026-01-03 13:35:24 +03:00
if ( toDeleteObject . has_value ( ) )
remove_bookmark ( toDeleteParent . value ( ) , toDeleteObject . value ( ) ) ;
2025-12-21 00:33:04 +03:00
}
2025-12-23 17:17:33 +03:00
gui . left_to_right_line_layout ( [ & ] ( ) {
bool addByEnter = false ;
gui . input_text ( " input new name " , & nameForNew , true , [ & ] ( GUIStuff : : SelectionHelper & s ) {
addByEnter = s . selected & & gui . io - > key . enter ;
} ) ;
if ( gui . svg_icon_button ( " create new bookmark " , " data/icons/plusbold.svg " , false , gui . SMALL_BUTTON_SIZE ) | | addByEnter )
2026-01-03 13:35:24 +03:00
create_bookmark ( new BookmarkListItem ( world . netObjMan , nameForNew , false , { world . drawData . cam . c , world . main . window . size . cast < int32_t > ( ) } ) ) ;
2025-12-23 17:17:33 +03:00
else if ( gui . svg_icon_button ( " create new folder " , " data/icons/folderbold.svg " , false , gui . SMALL_BUTTON_SIZE ) ) {
2026-01-03 13:35:24 +03:00
auto newFolderObjInfo = create_bookmark ( new BookmarkListItem ( world . netObjMan , nameForNew , true , { } ) ) ;
2025-12-23 17:17:33 +03:00
newFolderObjInfo - > obj - > set_folder_open ( true ) ;
}
} ) ;
if ( selectionData . objsSelected . size ( ) = = 1 ) {
NetObjTemporaryPtr < BookmarkListItem > tempPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( * selectionData . objsSelected . begin ( ) ) ;
if ( tempPtr ) {
gui . text_label_centered ( tempPtr - > is_folder ( ) ? " Edit Bookmark Folder " : " Edit Bookmark " ) ;
gui . input_text_field ( " input edit name " , " Name " , & nameToEdit ) ;
2025-12-24 12:42:27 +03:00
tempPtr - > set_name ( world . delayedUpdateObjectManager , nameToEdit ) ;
2025-12-23 17:17:33 +03:00
}
}
gui . pop_id ( ) ;
2025-12-21 00:33:04 +03:00
}
}
2026-01-03 13:35:24 +03:00
std : : optional < std : : pair < NetworkingObjects : : NetObjID , NetworkingObjects : : NetObjOrderedListIterator < BookmarkListItem > > > BookmarkManager : : try_to_create_in_proper_position ( BookmarkListItem * newItem ) {
2025-12-23 17:17:33 +03:00
using namespace NetworkingObjects ;
if ( selectionData . orderedObjsSelected . empty ( ) )
2025-12-30 19:46:08 +03:00
return std : : nullopt ;
2025-12-23 17:17:33 +03:00
auto & backObjParentObjectPair = selectionData . orderedObjsSelected . back ( ) ;
NetObjTemporaryPtr < BookmarkListItem > parentPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( backObjParentObjectPair . parent ) ;
if ( ! parentPtr )
2025-12-30 19:46:08 +03:00
return std : : nullopt ;
2025-12-23 17:17:33 +03:00
NetObjTemporaryPtr < BookmarkListItem > objectPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( backObjParentObjectPair . object ) ;
if ( ! objectPtr )
2025-12-30 19:46:08 +03:00
return std : : nullopt ;
2025-12-23 17:17:33 +03:00
if ( objectPtr - > is_folder ( ) ) {
objectPtr - > set_folder_open ( true ) ;
2026-01-03 13:35:24 +03:00
return std : : pair < NetworkingObjects : : NetObjID , NetworkingObjects : : NetObjOrderedListIterator < BookmarkListItem > > { objectPtr . get_net_id ( ) , objectPtr - > get_folder_list ( ) - > push_back_and_send_create ( objectPtr - > get_folder_list ( ) , newItem ) } ;
2025-12-23 17:17:33 +03:00
}
2026-01-03 13:35:24 +03:00
return std : : pair < NetworkingObjects : : NetObjID , NetworkingObjects : : NetObjOrderedListIterator < BookmarkListItem > > { parentPtr . get_net_id ( ) , parentPtr - > get_folder_list ( ) - > insert_and_send_create ( parentPtr - > get_folder_list ( ) , std : : next ( parentPtr - > get_folder_list ( ) - > get ( objectPtr . get_net_id ( ) ) ) , newItem ) } ;
2025-12-23 17:17:33 +03:00
}
2026-01-03 13:35:24 +03:00
std : : pair < NetworkingObjects : : NetObjID , NetworkingObjects : : NetObjOrderedListIterator < BookmarkListItem > > BookmarkManager : : create_in_proper_position ( BookmarkListItem * newItem ) {
2025-12-23 17:17:33 +03:00
auto toRet = try_to_create_in_proper_position ( newItem ) ;
if ( ! toRet )
2026-01-03 13:35:24 +03:00
return { bookmarkListRoot . get_net_id ( ) , bookmarkListRoot - > get_folder_list ( ) - > push_back_and_send_create ( bookmarkListRoot - > get_folder_list ( ) , newItem ) } ;
2025-12-30 19:46:08 +03:00
return toRet . value ( ) ;
2025-12-23 17:17:33 +03:00
}
2026-01-03 13:35:24 +03:00
NetworkingObjects : : NetObjOrderedListIterator < BookmarkListItem > BookmarkManager : : create_bookmark ( BookmarkListItem * newItem ) {
class AddBookmarkWorldUndoAction : public WorldUndoAction {
public :
AddBookmarkWorldUndoAction ( const BookmarkCompleteUndoData & initBookmarkData , uint32_t newPos , WorldUndoManager : : UndoObjectID initParentUndoID , WorldUndoManager : : UndoObjectID initUndoID ) :
bookmarkData ( initBookmarkData ) ,
pos ( newPos ) ,
parentUndoID ( initParentUndoID ) ,
undoID ( initUndoID )
{ }
std : : string get_name ( ) const override {
return bookmarkData . folderList ? " Add Bookmark Folder " : " Add Bookmark " ;
}
bool undo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toEraseParentID = undoMan . get_netid_from_undoid ( parentUndoID ) ;
if ( ! toEraseParentID . has_value ( ) )
return false ;
std : : optional < NetworkingObjects : : NetObjID > toEraseID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( ! toEraseID . has_value ( ) )
return false ;
auto & bookmarkList = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toEraseParentID . value ( ) ) - > get_folder_list ( ) ;
bookmarkList - > erase ( bookmarkList , bookmarkList - > get ( toEraseID . value ( ) ) ) ;
return true ;
}
bool redo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toInsertParentID = undoMan . get_netid_from_undoid ( parentUndoID ) ;
if ( ! toInsertParentID . has_value ( ) )
return false ;
std : : optional < NetworkingObjects : : NetObjID > toInsertID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( toInsertID . has_value ( ) )
return false ;
auto & bookmarkList = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toInsertParentID . value ( ) ) - > get_folder_list ( ) ;
auto insertedIt = bookmarkList - > emplace_direct ( bookmarkList , bookmarkList - > at ( pos ) , undoMan . world , bookmarkData ) ;
undoMan . register_new_netid_to_existing_undoid ( undoID , insertedIt - > obj . get_net_id ( ) ) ;
return true ;
}
void scale_up ( const WorldScalar & scaleAmount ) override {
bookmarkData . scale_up ( scaleAmount ) ;
}
~ AddBookmarkWorldUndoAction ( ) { }
BookmarkCompleteUndoData bookmarkData ;
uint32_t pos ;
WorldUndoManager : : UndoObjectID parentUndoID ;
WorldUndoManager : : UndoObjectID undoID ;
} ;
auto insertedBookmarkPair = create_in_proper_position ( newItem ) ;
auto & it = insertedBookmarkPair . second ;
world . undo . push ( std : : make_unique < AddBookmarkWorldUndoAction > ( it - > obj - > get_complete_undo_data ( world . undo ) , it - > pos , world . undo . get_undoid_from_netid ( insertedBookmarkPair . first ) , world . undo . get_undoid_from_netid ( it - > obj . get_net_id ( ) ) ) ) ;
return it ;
}
void BookmarkManager : : remove_bookmark ( const NetworkingObjects : : NetObjID & parentID , const NetworkingObjects : : NetObjID & objectID ) {
class DeleteBookmarkWorldUndoAction : public WorldUndoAction {
public :
DeleteBookmarkWorldUndoAction ( const BookmarkCompleteUndoData & initBookmarkData , uint32_t newPos , WorldUndoManager : : UndoObjectID initParentUndoID , WorldUndoManager : : UndoObjectID initUndoID ) :
bookmarkData ( initBookmarkData ) ,
pos ( newPos ) ,
parentUndoID ( initParentUndoID ) ,
undoID ( initUndoID )
{ }
std : : string get_name ( ) const override {
return bookmarkData . folderList ? " Delete Bookmark Folder " : " Delete Bookmark " ;
}
bool undo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toInsertParentID = undoMan . get_netid_from_undoid ( parentUndoID ) ;
if ( ! toInsertParentID . has_value ( ) )
return false ;
std : : optional < NetworkingObjects : : NetObjID > toInsertID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( toInsertID . has_value ( ) )
return false ;
auto & bookmarkList = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toInsertParentID . value ( ) ) - > get_folder_list ( ) ;
auto insertedIt = bookmarkList - > emplace_direct ( bookmarkList , bookmarkList - > at ( pos ) , undoMan . world , bookmarkData ) ;
undoMan . register_new_netid_to_existing_undoid ( undoID , insertedIt - > obj . get_net_id ( ) ) ;
return true ;
}
bool redo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toEraseParentID = undoMan . get_netid_from_undoid ( parentUndoID ) ;
if ( ! toEraseParentID . has_value ( ) )
return false ;
std : : optional < NetworkingObjects : : NetObjID > toEraseID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( ! toEraseID . has_value ( ) )
return false ;
auto & bookmarkList = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toEraseParentID . value ( ) ) - > get_folder_list ( ) ;
bookmarkList - > erase ( bookmarkList , bookmarkList - > get ( toEraseID . value ( ) ) ) ;
return true ;
}
void scale_up ( const WorldScalar & scaleAmount ) override {
bookmarkData . scale_up ( scaleAmount ) ;
}
~ DeleteBookmarkWorldUndoAction ( ) { }
BookmarkCompleteUndoData bookmarkData ;
uint32_t pos ;
WorldUndoManager : : UndoObjectID parentUndoID ;
WorldUndoManager : : UndoObjectID undoID ;
} ;
auto & folderList = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( parentID ) - > get_folder_list ( ) ;
auto it = folderList - > get ( objectID ) ;
world . undo . push ( std : : make_unique < DeleteBookmarkWorldUndoAction > ( it - > obj - > get_complete_undo_data ( world . undo ) , it - > pos , world . undo . get_undoid_from_netid ( parentID ) , world . undo . get_undoid_from_netid ( objectID ) ) ) ;
folderList - > erase ( folderList , it ) ;
}
2025-12-20 16:38:51 +03:00
void BookmarkManager : : scale_up ( const WorldScalar & scaleUpAmount ) {
2025-12-31 16:30:56 +03:00
bookmarkListRoot - > scale_up ( scaleUpAmount ) ;
2025-12-20 16:38:51 +03:00
}
2026-01-01 22:46:02 +03:00
void BookmarkManager : : save_file ( cereal : : PortableBinaryOutputArchive & a ) const {
bookmarkListRoot - > save_file ( a ) ;
}
void BookmarkManager : : load_file ( cereal : : PortableBinaryInputArchive & a , VersionNumber version ) {
2026-01-02 09:22:52 +03:00
if ( version > = VersionNumber ( 0 , 4 , 0 ) ) {
bookmarkListRoot = world . netObjMan . make_obj_from_ptr < BookmarkListItem > ( new BookmarkListItem ( ) ) ;
bookmarkListRoot - > load_file ( a , version , * this ) ;
}
else {
server_init_no_file ( ) ;
std : : unordered_map < std : : string , BookmarkData > bookmarkMap ;
std : : vector < std : : pair < std : : string , BookmarkData > > bookmarkDataSorted ;
a ( bookmarkMap ) ;
for ( auto & [ name , bData ] : bookmarkMap )
bookmarkDataSorted . emplace_back ( name , bData ) ;
std : : sort ( bookmarkDataSorted . begin ( ) , bookmarkDataSorted . end ( ) , [ ] ( auto & aPair , auto & bPair ) {
return aPair . first < bPair . first ;
} ) ;
for ( auto & [ name , bData ] : bookmarkDataSorted )
bookmarkListRoot - > get_folder_list ( ) - > push_back_and_send_create ( bookmarkListRoot - > get_folder_list ( ) , new BookmarkListItem ( world . netObjMan , name , false , bData ) ) ;
}
2026-01-01 22:46:02 +03:00
}
2026-01-03 13:35:24 +03:00
void BookmarkManager : : editing_bookmark_check ( ) {
class EditBookmarkWorldUndoAction : public WorldUndoAction {
public :
EditBookmarkWorldUndoAction ( const std : : string & initNameOld , const std : : string & initNameNew , WorldUndoManager : : UndoObjectID initUndoID ) :
nameOld ( initNameOld ) ,
nameNew ( initNameNew ) ,
undoID ( initUndoID )
{ }
std : : string get_name ( ) const override {
return " Edit Bookmark " ;
}
bool undo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toModifyID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( ! toModifyID . has_value ( ) )
return false ;
auto objPtr = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toModifyID . value ( ) ) ;
objPtr - > set_name ( undoMan . world . delayedUpdateObjectManager , nameOld ) ;
return true ;
}
bool redo ( WorldUndoManager & undoMan ) override {
std : : optional < NetworkingObjects : : NetObjID > toModifyID = undoMan . get_netid_from_undoid ( undoID ) ;
if ( ! toModifyID . has_value ( ) )
return false ;
auto objPtr = undoMan . world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( toModifyID . value ( ) ) ;
objPtr - > set_name ( undoMan . world . delayedUpdateObjectManager , nameNew ) ;
return true ;
}
~ EditBookmarkWorldUndoAction ( ) { }
std : : string nameOld ;
std : : string nameNew ;
WorldUndoManager : : UndoObjectID undoID ;
} ;
if ( oldSelection . size ( ) = = 1 & & editingBookmarkName . has_value ( ) ) {
const NetworkingObjects : : NetObjID & oldNetObjID = * oldSelection . begin ( ) ;
auto tempPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( oldNetObjID ) ;
if ( tempPtr ) {
const std : : string & currentNameData = tempPtr - > get_name ( ) ;
if ( currentNameData ! = editingBookmarkName . value ( ) )
world . undo . push ( std : : make_unique < EditBookmarkWorldUndoAction > ( editingBookmarkName . value ( ) , currentNameData , world . undo . get_undoid_from_netid ( oldNetObjID ) ) ) ;
}
}
editingBookmarkName = std : : nullopt ;
if ( selectionData . objsSelected . size ( ) = = 1 ) {
auto tempPtr = world . netObjMan . get_obj_temporary_ref_from_id < BookmarkListItem > ( * selectionData . objsSelected . begin ( ) ) ;
if ( tempPtr )
editingBookmarkName = tempPtr - > get_name ( ) ;
}
oldSelection = selectionData . objsSelected ;
}