// Finds a vector corresponding to a set of vertically aligned blob edges
// running through the given box. The type of vector returned and the
// search parameters are determined by the AlignedBlobParams.
// vertical_x and y are updated with an estimate of the real
// vertical direction. (skew finding.)
// Returns NULL if no decent vector can be found.
TabVector* AlignedBlob::FindVerticalAlignment(AlignedBlobParams align_params,
                                              BLOBNBOX* bbox,
                                              int* vertical_x,
                                              int* vertical_y) {
  int ext_start_y, ext_end_y;
  BLOBNBOX_CLIST good_points;
  // Search up and then down from the starting bbox.
  int pt_count = AlignTabs(align_params, false, bbox, &good_points, &ext_end_y);
  pt_count += AlignTabs(align_params, true, bbox, &good_points, &ext_start_y);
  BLOBNBOX_C_IT it(&good_points);
  it.move_to_last();
  int end_y = it.data()->bounding_box().top();
  it.move_to_first();
  int start_y = it.data()->bounding_box().bottom();
  if (pt_count >= align_params.min_points &&
      end_y - start_y >= align_params.min_length) {
    int confirmed_points = 0;
    // Count existing confirmed points to see if vector is acceptable.
    for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
      bbox = it.data();
      if (align_params.right_tab) {
        if (bbox->right_tab_type() == align_params.confirmed_type)
          ++confirmed_points;
      } else {
        if (bbox->left_tab_type() == align_params.confirmed_type)
          ++confirmed_points;
      }
    }
    // Ragged vectors are not allowed to use too many already used points.
    if (!align_params.ragged ||
        confirmed_points + confirmed_points < pt_count) {
      const TBOX& box = bbox->bounding_box();
      if (WithinTestRegion(2, box.left(), box.bottom())) {
        tprintf("Confirming tab vector of %d pts starting at %d,%d\n",
                pt_count, box.left(), box.bottom());
      }
      // Flag all the aligned neighbours as confirmed .
      for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
        bbox = it.data();
        if (align_params.right_tab) {
          bbox->set_right_tab_type(align_params.confirmed_type);
        } else {
          bbox->set_left_tab_type(align_params.confirmed_type);
        }
      }
      // Now make the vector and return it.
      TabVector* result = TabVector::FitVector(align_params.alignment,
                                               align_params.vertical,
                                               ext_start_y, ext_end_y,
                                               &good_points,
                                               vertical_x, vertical_y);
      if (WithinTestRegion(2, box.left(), box.bottom())) {
        result->Print("After fitting");
      }
      return result;
    }
  }
  return NULL;
}
void AngelGUISystem::GUI2D::AGTabGroup::Update(float dt)
{
	if (m_recreate)
	{
		//m_tabBackground->SetRectangle(m_rectangle);
		//m_tabBackground->SetPosition(m_position);
		m_tabHeader->SetRectangle(0, 0, m_rectangle.right, 20);
		m_tabHeader->SetPosition(m_position.x, m_position.y - 40);
		
		AlignTabs();
		AlignHeaders();
		m_recreate = false;
	}
}
void AngelGUISystem::GUI2D::AGTabGroup::AddTab(AngelGUISystem::GUI2D::AGTab* item)
{
	static TSpecificFunctor<AGTabGroup> specFuncA(&*this, &AGTabGroup::TabChanged);
	
	item->m_isInTabGroupe = true;
	item->SetPosition(m_position);
	item->SetRectangle(m_rectangle);
	AGButton * tabHeader = new AGButton();
	tabHeader->Initialize();
	tabHeader->RegisterCallBackFunction(&specFuncA);
	tabHeader->SetText(item->GetTabHeader()->GetText().c_str());
	m_tabGroupeHeaders.push_back(tabHeader);
	AlignTabs();
	m_tabs.push_back(item);
	AlignHeaders();
	FocusOnSelectedTab();
}
// Finds a vector corresponding to a set of vertically aligned blob edges
// running through the given box. The type of vector returned and the
// search parameters are determined by the AlignedBlobParams.
// vertical_x and y are updated with an estimate of the real
// vertical direction. (skew finding.)
// Returns nullptr if no decent vector can be found.
TabVector* AlignedBlob::FindVerticalAlignment(AlignedBlobParams align_params,
                                              BLOBNBOX* bbox,
                                              int* vertical_x,
                                              int* vertical_y) {
  int ext_start_y, ext_end_y;
  BLOBNBOX_CLIST good_points;
  // Search up and then down from the starting bbox.
  TBOX box = bbox->bounding_box();
  bool debug = WithinTestRegion(2, box.left(), box.bottom());
  int pt_count = AlignTabs(align_params, false, bbox, &good_points, &ext_end_y);
  pt_count += AlignTabs(align_params, true, bbox, &good_points, &ext_start_y);
  BLOBNBOX_C_IT it(&good_points);
  it.move_to_last();
  box = it.data()->bounding_box();
  int end_y = box.top();
  int end_x = align_params.right_tab ? box.right() : box.left();
  it.move_to_first();
  box = it.data()->bounding_box();
  int start_x = align_params.right_tab ? box.right() : box.left();
  int start_y = box.bottom();
  // Acceptable tab vectors must have a minimum number of points,
  // have a minimum acceptable length, and have a minimum gradient.
  // The gradient corresponds to the skew angle.
  // Ragged tabs don't need to satisfy the gradient condition, as they
  // will always end up parallel to the vertical direction.
  bool at_least_2_crossings = AtLeast2LineCrossings(&good_points);
  if ((pt_count >= align_params.min_points &&
      end_y - start_y >= align_params.min_length &&
      (align_params.ragged ||
          end_y - start_y >= abs(end_x - start_x) * kMinTabGradient)) ||
      at_least_2_crossings) {
    int confirmed_points = 0;
    // Count existing confirmed points to see if vector is acceptable.
    for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
      bbox = it.data();
      if (align_params.right_tab) {
        if (bbox->right_tab_type() == align_params.confirmed_type)
          ++confirmed_points;
      } else {
        if (bbox->left_tab_type() == align_params.confirmed_type)
          ++confirmed_points;
      }
    }
    // Ragged vectors are not allowed to use too many already used points.
    if (!align_params.ragged ||
        confirmed_points + confirmed_points < pt_count) {
      const TBOX& box = bbox->bounding_box();
      if (debug) {
        tprintf("Confirming tab vector of %d pts starting at %d,%d\n",
                pt_count, box.left(), box.bottom());
      }
      // Flag all the aligned neighbours as confirmed .
      for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
        bbox = it.data();
        if (align_params.right_tab) {
          bbox->set_right_tab_type(align_params.confirmed_type);
        } else {
          bbox->set_left_tab_type(align_params.confirmed_type);
        }
        if (debug) {
          bbox->bounding_box().print();
        }
      }
      // Now make the vector and return it.
      TabVector* result = TabVector::FitVector(align_params.alignment,
                                               align_params.vertical,
                                               ext_start_y, ext_end_y,
                                               &good_points,
                                               vertical_x, vertical_y);
      result->set_intersects_other_lines(at_least_2_crossings);
      if (debug) {
        tprintf("Box was %d, %d\n", box.left(), box.bottom());
        result->Print("After fitting");
      }
      return result;
    } else if (debug) {
      tprintf("Ragged tab used too many used points: %d out of %d\n",
              confirmed_points, pt_count);
    }
  } else if (debug) {
    tprintf("Tab vector failed basic tests: pt count %d vs min %d, "
            "length %d vs min %d, min grad %g\n",
            pt_count, align_params.min_points, end_y - start_y,
            align_params.min_length, abs(end_x - start_x) * kMinTabGradient);
  }
  return nullptr;
}