///////////////////////////////////////////////////////////////////////////// // Name: range.cpp // Purpose: Simple min-max range class and associated selection array class // Author: John Labenski // Created: 12/01/2000 // Copyright: (c) John Labenski 2004 // Licence: wxWidgets ///////////////////////////////////////////////////////////////////////////// #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "range.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/utils.h" #endif // WX_PRECOMP #include "wx/things/range.h" #include const wxRangeInt wxEmptyRangeInt(0, -1); const wxRangeDouble wxEmptyRangeDouble(0, -1); #include "wx/arrimpl.cpp" WX_DEFINE_OBJARRAY(wxArrayRangeInt); WX_DEFINE_OBJARRAY(wxArrayRangeDouble); WX_DEFINE_OBJARRAY(wxArrayRangeIntSelection); WX_DEFINE_OBJARRAY(wxArrayRangeDoubleSelection); // set this if you want to double check that that ranges are really working //#define CHECK_RANGES //============================================================================= // wxRangeInt //============================================================================= bool wxRangeInt::Combine(int i, bool only_if_touching) { if (only_if_touching) { if (i == m_min-1) { m_min--; return true; } else if (i == m_max+1) { m_max++; return true; } } else { if (i < m_min) { m_min = i; return true; } else if (i > m_max) { m_max = i; return true; } } return false; } bool wxRangeInt::Combine( const wxRangeInt &r, bool only_if_touching ) { if (only_if_touching) { if (Touches(r)) { *this+=r; return true; } } else { bool added = false; if (r.m_min < m_min) { m_min = r.m_min; added = true; } if (r.m_max > m_max) { m_max = r.m_max; added = true; } return added; } return false; } bool wxRangeInt::Delete( const wxRangeInt &r, wxRangeInt *right ) { if (!Contains(r)) return false; if (right) *right = wxEmptyRangeInt; if (r.m_min <= m_min) { if (r.m_max >= m_max) { *this = wxEmptyRangeInt; return true; } m_min = r.m_max + 1; return true; } if (r.m_max >= m_max) { m_max = r.m_min - 1; return true; } if (right) *right = wxRangeInt(r.m_max + 1, m_max); m_max = r.m_min - 1; return true; } //============================================================================= // wxRangeIntSelection //============================================================================= const wxRangeInt& wxRangeIntSelection::GetRange( int index ) const { wxCHECK_MSG((index>=0) && (index m_ranges[count-1].m_max) return wxNOT_FOUND; // Binary search int res, tmp, lo = 0, hi = count; while ( lo < hi ) { tmp = (lo + hi)/2; res = m_ranges[tmp].Position(i); if (res == 0) return tmp; else if ( res < 0 ) hi = tmp; else //if ( res > 0 ) lo = tmp + 1; } return wxNOT_FOUND; } int wxRangeIntSelection::Index( const wxRangeInt &r ) const { register int i, count = m_ranges.GetCount(); for (i=0; i m_ranges[count-1].m_max) return count; // Binary search int res, tmp, lo = 0, hi = count; while ( lo < hi ) { tmp = (lo + hi)/2; res = m_ranges[tmp].Position(i); if ( res == 0 ) return tmp; else if ((i >= m_ranges[tmp].m_max) && (i < m_ranges[wxMin(tmp+1, count-1)].m_min)) return tmp; else if ( res < 0 ) hi = tmp; else //if ( res > 0 ) lo = tmp + 1; } // oops shouldn't get here wxCHECK_MSG(0, -1, wxT("Error calculating NearestIndex in wxRangeIntSelection")); } int wxRangeIntSelection::GetItemCount() const { register int i, items = 0, count = m_ranges.GetCount(); for (i=0; i 0 ? NearestIndex(range.m_min) : -1; if ((nearest < 0) || (nearest == count)) return false; wxRangeInt r; for (i=nearest; i 0) ? i-1 : -1; } else if (!r.IsEmpty()) m_ranges.Insert(r, i+1); done = true; } } return done; } bool wxRangeIntSelection::SelectRange(const wxRangeInt &range) { wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") ); // Try to find a range that includes this one and combine it, else insert it, else append it bool done = false; int i, count = m_ranges.GetCount(); int nearest = count > 0 ? NearestIndex(range.m_min) : -1; if (nearest < 0) { if (!((count > 0) && m_ranges[0].Combine(range, true))) m_ranges.Insert(range, 0); return true; } else if (nearest == count) { if (!((count > 0) && m_ranges[count-1].Combine(range, true))) m_ranges.Add(range); return true; } else { if (m_ranges[nearest].Contains(range)) return false; for (i=nearest; i= range.m_min) break; if (m_ranges[i].m_max < range.m_min) // range is out of bounds { done = true; m_ranges.RemoveAt(i); count--; i--; } else { done = true; m_ranges[i].m_min = range.m_min; break; } } for (i = m_ranges.GetCount() - 1; i >= 0; i--) { if (m_ranges[i].m_max <= range.m_max) break; if (m_ranges[i].m_min > range.m_max) // range is out of bounds { done = true; m_ranges.RemoveAt(i); } else { done = true; m_ranges[i].m_max = range.m_max; break; } } return done; } //============================================================================= // wxRangeDouble //============================================================================= bool wxRangeDouble::Combine(double i) { if (i < m_min) { m_min = i; return true; } else if (i > m_max) { m_max = i; return true; } return false; } bool wxRangeDouble::Combine( const wxRangeDouble &r, bool only_if_touching ) { if (only_if_touching) { if (Contains(r)) { *this+=r; return true; } } else { bool added = false; if (r.m_min < m_min) { m_min = r.m_min; added = true; } if (r.m_max > m_max) { m_max = r.m_max; added = true; } return added; } return false; } bool wxRangeDouble::Delete( const wxRangeDouble &r, wxRangeDouble *right ) { if (!Contains(r)) return false; if (right) *right = wxEmptyRangeDouble; if (r.m_min <= m_min) { if (r.m_max >= m_max) { *this = wxEmptyRangeDouble; return true; } m_min = r.m_max; return true; } if (r.m_max >= m_max) { m_max = r.m_min; return true; } if (right) *right = wxRangeDouble(r.m_max, m_max); m_max = r.m_min; return true; } //============================================================================= // wxRangeDoubleSelection //============================================================================= const wxRangeDouble& wxRangeDoubleSelection::GetRange( int index ) const { wxCHECK_MSG((index>=0) && (index m_ranges[count-1].m_max) return wxNOT_FOUND; // Binary search int res, tmp, lo = 0, hi = count; while ( lo < hi ) { tmp = (lo + hi)/2; res = m_ranges[tmp].Position(i); if ( res == 0 ) return tmp; else if ( res < 0 ) hi = tmp; else //if ( res > 0 ) lo = tmp + 1; } return wxNOT_FOUND; /* for (register int j=0; j m_ranges[count-1].m_max) return count; // Binary search int res, tmp, lo = 0, hi = count; while ( lo < hi ) { tmp = (lo + hi)/2; res = m_ranges[tmp].Position(i); if ( res == 0 ) return tmp; else if ((i >= m_ranges[tmp].m_max) && (i < m_ranges[wxMin(tmp+1, count-1)].m_min)) return tmp; else if ( res < 0 ) hi = tmp; else //if ( res > 0 ) lo = tmp + 1; } // oops shouldn't get here wxCHECK_MSG(0, -1, wxT("Error calculating NearestIndex in wxRangeDoubleSelection")); } bool wxRangeDoubleSelection::SelectRange(const wxRangeDouble &range) { wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") ); // Try to find a range that includes this one and combine it, else insert it, else append it bool done = false; int i, count = m_ranges.GetCount(); int nearest = count > 0 ? NearestIndex(range.m_min) : -1; if (nearest < 0) { if (!((count > 0) && m_ranges[0].Combine(range, true))) m_ranges.Insert(range, 0); return true; } else if (nearest == count) { if (!((count > 0) && m_ranges[count-1].Combine(range, true))) m_ranges.Add(range); return true; } else { if (m_ranges[nearest].Contains(range)) return false; for (i=nearest; i 0 ? NearestIndex(range.m_min) : -1; if ((nearest < 0) || (nearest == count)) return false; wxRangeDouble r; for (i=nearest; i 0) ? i-1 : -1; } else if (!r.IsEmpty()) m_ranges.Insert(r, i+1); done = true; } } return done; } bool wxRangeDoubleSelection::BoundRanges(const wxRangeDouble& range) { wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Bounding Range") ); int i, count = m_ranges.GetCount(); bool done = false; for (i = 0; i < count; i++) { if (m_ranges[i].m_min >= range.m_min) break; if (m_ranges[i].m_max < range.m_min) // range is out of bounds { done = true; m_ranges.RemoveAt(i); count--; i--; } else { done = true; m_ranges[i].m_min = range.m_min; break; } } for (i = m_ranges.GetCount() - 1; i >= 0; i--) { if (m_ranges[i].m_max <= range.m_max) break; if (m_ranges[i].m_min > range.m_max) // range is out of bounds { done = true; m_ranges.RemoveAt(i); } else { done = true; m_ranges[i].m_max = range.m_max; break; } } return done; }