virtual void render() {
   gps.erasescreen();
   drawborder("Matrix", 1, 0);
   for (lit i = lines.begin(); i != lines.end(); ++i) {
     for (int j = 0; j < i->s.size(); ++j) {
       gps.addchar(i->x, i->y + j, i->s[j], i->color, 0, 0);
     }
   }
 }
void ViewWidgets::setclip() {
 clipx[0]=gps.clipx[0];
 clipx[1]=gps.clipx[1];
 clipy[0]=gps.clipy[0];
 clipy[1]=gps.clipy[1];
 gps.setclipping(x,x2,y,y2);
}
void ScrollListWidget::render(void* param) {
 setclip();
 if (DoClear) gps.erasescreen_clip();
 int X=x;
 int Y=y;
 int i=PageStart;
 gps.locate(Y,X);
 char store[256];
 while (i<PageEnd) {
  if (i==count) break;
  const char* str=ListSrc->ListItem(i,param,store);
  if (i==selected) {
   if (HasFocus) gps.changecolor(FSelColorF, FSelColorB, FSelColorH);
   else gps.changecolor(SelColorF, SelColorB, SelColorH);
  } else gps.changecolor(ColorF, ColorB, ColorH);
  while (1) {
   gps.addchar(*str,1);
   if (*str) {
    str++;
    if (!(*str)) if (!ColorBlanks) break;
   }
   if (gps.screenx==x2) break;
  }
  ++i;
  gps.locate(++Y,X);
 }
 releaseclip();
}
void TabBarWidget::render(void* param) {
 setclip();
 if (DoClear) gps.erasescreen_clip();
 int X=x;
 int Y=y;
 int i=PageStart;
 gps.locate(Y,X);
 char store[256];
 while (i<PageEnd) {
  if (i==count) break;
  const char* str=ListSrc->ListItem(i,param,store);
  int len=spacing;
  if (X+len>=x2) {
   X=x;
   ++Y;
   if (Y>y2) break;
   gps.locate(Y,X);
  }
  if (i==selected) {
   if (HasFocus) gps.changecolor(FSelColorF, FSelColorB, FSelColorH);
   else gps.changecolor(SelColorF, SelColorB, SelColorH);
  } else gps.changecolor(ColorF, ColorB, ColorH);
  while (len) {
   gps.addchar(*str,1);
   if (*str) {
    str++;
    if (!*str) if (!ColorBlanks) {
     X=gps.screenx;
     gps.locate(Y,X+len);
     break;
    }
   }
   --len;
  }
  ++i;
  X=gps.screenx;
 }
 releaseclip();
}
void drawborder(const char *str, char style, const char *color) {
  gps.erasescreen();
  if (style) {
    gps.changecolor(7,7,0);
    for (int x=0; x < gps.dimx; x++) {
      gps.locate(0, x);
      gps.addchar(' ');
      gps.locate(gps.dimy-1, x);
      gps.addchar(' ');
    }
    for (int y=1; y < gps.dimy-1; y++) {
      gps.locate(y, 0);
      gps.addchar(' ');
      gps.locate(y, gps.dimx-1);
      gps.addchar(' ');
    }
  }
  if (!str) return;
  gps.locate(0, MAX((gps.dimx - strlen(str)) / 2,0));
  if (color)
    gps.addcoloredst(str, color);
  else {
    gps.changecolor(7,0,1);
    gps.addst(str);
  }
}
void ViewWidgets::releaseclip(){
 gps.setclipping(clipx[0],clipx[1],clipy[0],clipy[1]);
}
void render_things()
{
  //GRAB CURRENT SCREEN AT THE END OF THE LIST
  viewscreenst *currentscreen=&gview.view;
  while(currentscreen->child!=NULL)currentscreen=currentscreen->child;
  
  //NO INTERFACE LEFT, LEAVE
  if(currentscreen==&gview.view)return;
  
  if(currentscreen->breakdownlevel==INTERFACE_BREAKDOWN_NONE)
	{
	currentscreen->render();
	}
  else gps.erasescreen();

  // Render REC when recording macros. Definitely want this screen-specific. Or do we?
  const Time now = SDL_GetTicks();
  if (enabler.is_recording() && now % 1000 > 500) {
    gps.locate(0, 20);
    gps.changecolor(4,1,1);
    gps.addst("REC");
  }
  // Render PLAY when playing a macro
  if (enabler.is_macro_playing() && now % 1000 <= 500) {
    gps.locate(0,20);
    gps.changecolor(2,1,1);
    gps.addst("PLAY");
  }
  // Render # <i> when building a repetition prefix
  if (enabler.prefix_building()) {
    gps.locate(0,20);
    gps.changecolor(3,1,1);
    gps.addst("#" + enabler.prefix());
  }
  if (gps.display_frames) {
    ostringstream fps_stream;
    fps_stream << "FPS: " << setw(3) << enabler.calculate_fps() << " (" << enabler.calculate_gfps() << ")";
    string fps = fps_stream.str();
    gps.changecolor(7,3,1);
    static gps_locator fps_locator(0, 25);
    fps_locator(fps.size());
    gps.addst(fps);
  }
}