GME
13
|
00001 #include "stdafx.h" 00002 00003 #include "GMEApp.h" 00004 #include "GMEStd.h" 00005 #include "GuiObject.h" 00006 #include "ModelGrid.h" 00007 00009 00010 CModelGrid::CModelGrid() 00011 { 00012 #ifdef GRIDBITS 00013 width = GME_MAX_GRID_DIM / (8 * sizeof(int)); 00014 #else 00015 width = GME_MAX_GRID_DIM; 00016 #endif 00017 height = GME_MAX_GRID_DIM; 00018 Clear(); 00019 view = 0; 00020 } 00021 00022 #ifdef GRIDBITS 00023 00024 #define trafo() ASSERT(sizeof(int) == 4); \ 00025 unsigned int xi = (x >> 5); \ 00026 ASSERT(xi < (unsigned int)width); \ 00027 ASSERT(y < height); \ 00028 unsigned int mask = 1 << ((unsigned int)x & 0x1F); 00029 00030 inline bool CModelGrid::IsAvailable(int x,int y) 00031 { 00032 trafo(); 00033 return ((grid[y][xi] & mask) == 0); 00034 } 00035 00036 inline void CModelGrid::Set(int x,int y) 00037 { 00038 trafo(); 00039 grid[y][xi] |= mask; 00040 } 00041 00042 inline void CModelGrid::Reset(int x,int y) 00043 { 00044 trafo(); 00045 mask = ~mask; 00046 grid[y][xi] &= mask; 00047 } 00048 00049 #else 00050 00051 inline bool CModelGrid::IsAvailable(int x,int y) 00052 { 00053 return !grid[y][x]; 00054 } 00055 00056 inline void CModelGrid::Set(int x,int y) 00057 { 00058 grid[y][x] = true; 00059 } 00060 00061 inline void CModelGrid::Reset(int x,int y) 00062 { 00063 grid[y][x] = false; 00064 } 00065 00066 #endif 00067 00068 void CModelGrid::Clear() 00069 { 00070 int i; 00071 memset(grid,0,sizeof(grid)); 00072 for(i = 0; i < width; i++) { // frame! 00073 #ifdef GRIDBITS 00074 grid[0][i] = (unsigned int)~0; 00075 grid[height - 1][i] = (unsigned int)~0; 00076 #else 00077 Set(i,0); 00078 Set(i,GME_MAX_GRID_DIM-1); 00079 #endif 00080 } 00081 for(i = 0; i < height; i++) { 00082 Set(0,i); 00083 Set(GME_MAX_GRID_DIM-1,i); 00084 } 00085 view = 0; 00086 } 00087 00088 bool CModelGrid::IsAvailableG(CPoint &pt,CSize &size) 00089 { 00090 int startx = pt.x; 00091 int starty = pt.y; 00092 int endx = pt.x + size.cx; 00093 int endy = pt.y + size.cy; 00094 // Hack to prevent labels from overlapping 00095 //starty -= 2; 00096 if(startx < 0 || starty < 0 || endx >= GME_MAX_GRID_DIM || endy >= GME_MAX_GRID_DIM) 00097 return false; 00098 for(int i = starty; i <= endy; i++) 00099 for(int j = startx; j <= endx; j++) 00100 if(!IsAvailable(j,i)) 00101 return false; 00102 return true; 00103 } 00104 00105 00106 #define FindStartEnd(rect,chk) \ 00107 int startx = (rect.left / GME_GRID_SIZE); \ 00108 int starty = (rect.top / GME_GRID_SIZE); \ 00109 int endx = ((rect.right + GME_GRID_SIZE - 1) / GME_GRID_SIZE); \ 00110 int endy = ((rect.bottom + GME_GRID_SIZE - 1) / GME_GRID_SIZE); \ 00111 if(chk) { \ 00112 ASSERT(startx >= 0); \ 00113 ASSERT(starty >= 0); \ 00114 ASSERT(endx < GME_MAX_GRID_DIM); \ 00115 ASSERT(endy < GME_MAX_GRID_DIM); \ 00116 } 00117 00118 00119 bool CModelGrid::IsAvailable(const CRect& rect) 00120 { 00121 FindStartEnd(rect,0); 00122 if(startx < 0 || starty < 0 || (unsigned int)endx >= GME_MAX_GRID_DIM || (unsigned int)endy >= GME_MAX_GRID_DIM) 00123 return false; 00124 for(int y = starty; y <= endy; y++) 00125 for(int x = startx; x <= endx; x++) 00126 if(!IsAvailable(x,y)) 00127 return false; 00128 return true; 00129 } 00130 00131 00132 #define test_and_return_if_found() \ 00133 if(IsAvailableG(test,size)) { \ 00134 rect.MoveToXY(test.x * GME_GRID_SIZE, test.y * GME_GRID_SIZE); \ 00135 return TRUE; \ 00136 } 00137 00138 bool CModelGrid::GetClosestAvailable(CRect& rect) 00139 { 00140 if(IsAvailable(rect)) { 00141 rect.MoveToXY((rect.left / GME_GRID_SIZE) * GME_GRID_SIZE, 00142 (rect.top / GME_GRID_SIZE) * GME_GRID_SIZE); 00143 return TRUE; 00144 } 00145 00146 CPoint pt = rect.TopLeft(); 00147 pt.x /= GME_GRID_SIZE; 00148 pt.y /= GME_GRID_SIZE; 00149 pt.x = max(0,min(GME_MAX_GRID_DIM - 1,pt.x)); 00150 pt.y = max(0,min(GME_MAX_GRID_DIM - 1,pt.y)); 00151 CSize size = rect.Size(); 00152 size.cx = (size.cx + GME_GRID_SIZE - 1) / GME_GRID_SIZE; 00153 size.cy = (size.cy + GME_GRID_SIZE - 1) / GME_GRID_SIZE; 00154 CPoint test = pt; 00155 for(int rad = 1; rad < GME_MAX_GRID_DIM; rad++) { 00156 test.x = pt.x - rad; 00157 if(test.x >= 0) 00158 for(test.y = max(0,pt.y - rad); test.y < min(GME_MAX_GRID_DIM,pt.y + rad + 1); test.y++) 00159 test_and_return_if_found(); 00160 test.x = pt.x + rad; 00161 if(test.x < GME_MAX_GRID_DIM) 00162 for(test.y = max(0,pt.y - rad); test.y < min(GME_MAX_GRID_DIM,pt.y + rad + 1); test.y++) 00163 test_and_return_if_found(); 00164 test.y = pt.y - rad; 00165 if(test.y >= 0) 00166 for(test.x = max(0,pt.x - rad) + 1; test.x < min(GME_MAX_GRID_DIM,pt.x + rad + 1) - 1; test.x++) 00167 test_and_return_if_found(); 00168 test.y = pt.y + rad; 00169 if(test.y < GME_MAX_GRID_DIM) 00170 for(test.x = max(0,pt.x - rad) + 1; test.x < min(GME_MAX_GRID_DIM,pt.x + rad + 1) - 1; test.x++) 00171 test_and_return_if_found(); 00172 } 00173 return FALSE; 00174 } 00175 00176 00177 void CModelGrid::Set(CRect& rect, bool reset) 00178 { 00179 FindStartEnd(rect,1); 00180 for(int y = starty; y <= endy; y++) 00181 for(int x = startx; x <= endx; x++) 00182 reset ? Reset(x,y) : Set(x,y); 00183 } 00184 00185 00186 00188 // Public methods - accepts objects as parameters 00189 00190 /* 00191 Mod by ZolMol: If called from CGMEView::SyncOnGrid then 00192 the object (*model) might not have the same aspects as its parent so 00193 calling GetLocation or GetNameLocation with default parameter might 00194 cause null ptr dereferencing 00195 */ 00196 void CModelGrid::Set(CGuiObject *model,bool reset, int aspIdx) 00197 { 00198 CRect loc = model->GetLocation( aspIdx); 00199 Set(loc,reset); 00200 00201 if (theApp.labelAvoidance) { 00202 loc = model->GetNameLocation( aspIdx); 00203 Set(loc, reset); 00204 } 00205 } 00206 00207 void CModelGrid::Reset(CGuiObject *model) 00208 { 00209 Set(model,TRUE); 00210 } 00211 00212 bool CModelGrid::IsAvailable(CGuiObject *model, int aspIdx) 00213 { 00214 CRect rect = model->GetLocation(aspIdx); 00215 bool avail = modelGrid.IsAvailable(rect); 00216 00217 if (theApp.labelAvoidance) { 00218 rect = model->GetNameLocation(aspIdx); 00219 avail = avail && modelGrid.IsAvailable(rect); 00220 } 00221 00222 return avail; 00223 } 00224 00225 /* 00226 Mod by ZolMol: If called from CGMEView::SyncOnGrid then 00227 the object (*model) might not have the same aspects as its parent so 00228 calling GetLocation or GetNameLocation with default parameter might 00229 cause null ptr dereferencing 00230 */ 00231 bool CModelGrid::GetClosestAvailable(CGuiObject *model, CRect &rect, int aspIdx) 00232 { 00233 bool ret = GetClosestAvailable(rect); 00234 00235 return ret; 00236 } 00237 00238 bool CModelGrid::CanNudge(CGuiObject *model,int right,int down) 00239 { 00240 ASSERT(right == 0 || down == 0); // no diagonal nudge! 00241 CRect r = model->GetLocation(); // comment by ZolMol: this is correct since the parent aspect is always valid, and an object is moved (nudged) within the parents aspect only 00242 right *= GME_GRID_SIZE; 00243 down *= GME_GRID_SIZE; 00244 r.right += right; 00245 r.left += right; 00246 r.top += down; 00247 r.bottom += down; 00248 bool can = IsAvailable(r); 00249 00250 if (theApp.labelAvoidance) { 00251 r = model->GetNameLocation(); 00252 r.right += right; 00253 r.left += right; 00254 r.top += down; 00255 r.bottom += down; 00256 can = can && IsAvailable(r); 00257 } 00258 00259 return can; 00260 }