/* 4coder_layout.cpp - Implementation of basic lookup routines on line layout data. */ // TOP internal i64 layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){ i64 closest_match = 0; if (p.y < 0.f){ closest_match = list.manifested_index_range.min; } else if (p.y >= list.height){ closest_match = list.manifested_index_range.max; } else{ if (0.f < p.x && p.x < max_f32){ f32 closest_x = -max_f32; for (Layout_Item_Block *block = list.first; block != 0; block = block->next){ i64 count = block->item_count; Layout_Item *item = block->items; for (i32 i = 0; i < count; i += 1, item += 1){ if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){ continue; } // NOTE(allen): This only works if we build layouts in y-sorted order. if (p.y < item->rect.y0){ goto double_break; } if (item->padded_y1 <= p.y){ continue; } f32 dist0 = p.x - item->rect.x0; f32 dist1 = item->rect.x1 - p.x; if (dist0 >= 0.f && dist1 > 0.f){ closest_match = item->index; goto double_break; } // NOTE(allen): One of dist0 and dist1 are negative, but certainly not both. // 1. Take the negative one. // 2. If the negative distance is larger than closest_x, then this is closer. f32 neg_dist = Min(dist0, dist1); if (closest_x < neg_dist){ closest_x = neg_dist; closest_match = item->index; } } } double_break:; } else{ if (p.x == max_f32){ Layout_Item *prev_item = 0; for (Layout_Item_Block *block = list.first; block != 0; block = block->next){ i64 count = block->item_count; Layout_Item *item = block->items; for (i32 i = 0; i < count; i += 1, item += 1){ if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){ continue; } if (p.y < item->rect.y0){ goto double_break_2; } prev_item = item; if (item->padded_y1 <= p.y){ continue; } } } double_break_2:; if (prev_item != 0){ closest_match = prev_item->index; } else{ closest_match = list.manifested_index_range.max; } } else{ Layout_Item *closest_item = 0; for (Layout_Item_Block *block = list.first; block != 0; block = block->next){ i64 count = block->item_count; Layout_Item *item = block->items; for (i32 i = 0; i < count; i += 1, item += 1){ if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){ continue; } // NOTE(allen): This only works if we build layouts in y-sorted order. if (p.y < item->rect.y0){ goto double_break_3; } if (item->padded_y1 <= p.y){ continue; } closest_item = item; goto double_break_3; } } double_break_3:; if (closest_item != 0){ closest_match = closest_item->index; } else{ closest_match = list.manifested_index_range.min; } } } } return(closest_match); } internal Layout_Item* layout_get_first_with_index(Layout_Item_List list, i64 index){ Layout_Item *result = 0; Layout_Item *prev = 0; for (Layout_Item_Block *block = list.first; block != 0; block = block->next){ i64 count = block->item_count; Layout_Item *item = block->items; for (i32 i = 0; i < count; i += 1, item += 1){ if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){ continue; } if (item->index > index){ result = prev; goto done; } if (item->index == index){ result = item; goto done; } prev = item; } } if (result == 0){ result = prev; } done:; return(result); } internal Rect_f32 layout_box_of_pos(Layout_Item_List list, i64 index){ Rect_f32 result = {}; Layout_Item *item = layout_get_first_with_index(list, index); if (item != 0){ result = item->rect; } return(result); } function Rect_f32 layout_padded_box_of_pos(Layout_Item_List list, i64 index){ Rect_f32 result = {}; Layout_Item *item = layout_get_first_with_index(list, index); if (item != 0){ result.x0 = item->rect.x0; result.y0 = item->rect.y0; result.x1 = item->rect.x1; result.y1 = item->padded_y1; } return(result); } internal i64 layout_get_pos_at_character(Layout_Item_List list, i64 character){ i64 result = 0; if (character <= 0){ result = list.manifested_index_range.min; } else if (character >= list.character_count){ result = list.manifested_index_range.max; } else{ i64 counter = 0; i64 next_counter = 0; for (Layout_Item_Block *node = list.first; node != 0; node = node->next, counter = next_counter){ next_counter = counter + node->character_count; if (character >= next_counter){ continue; } i64 count = node->item_count; i64 relative_character = character - counter; i64 relative_character_counter = 0; Layout_Item *item = node->items; for (i64 i = 0; i < count; i += 1, item += 1){ if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){ continue; } if (relative_character_counter == relative_character){ result = item->index; break; } relative_character_counter += 1; } break; } } return(result); } internal i64 layout_character_from_pos(Layout_Item_List list, i64 index){ i64 result = 0; i64 prev_index = -1; if (index <= list.manifested_index_range.first){ result = 0; } else if (index > list.manifested_index_range.one_past_last){ result = list.character_count - 1; } else{ for (Layout_Item_Block *node = list.first; node != 0; node = node->next){ Layout_Item *item = node->items; i64 count = node->item_count; for (i64 i = 0; i < count; i += 1, item += 1){ if (item->index >= index){ goto double_break; } if (item->index > prev_index){ prev_index = item->index; result += 1; } } } } double_break:; return(result); } // BOTTOM