07 - Text field 源码

#include <stdlib.h>
#include <string.h>
#include "SDL.h"

// If you're going to render widgets to the same
// UI from different source files, you can avoid
// ID collisions by defining IMGUI_SRC_ID before
// this define block:
#ifdef IMGUI_SRC_ID
#define GEN_ID ((IMGUI_SRC_ID) + (__LINE__))
#else
#define GEN_ID (__LINE__)
#endif

// Screen surface
SDL_Surface *gScreen;

// Font surface
SDL_Surface *gFont;

struct UIState
{
  int mousex;
  int mousey;
  int mousedown;

  int hotitem;
  int activeitem;

  int kbditem;
  int keyentered;
  int keymod;
  int keychar;
  
  int lastwidget;
} 
uistate = {0,0,0,0,0,0,0,0,0};

// Draw a single character.
// Characters are on top of each other in the font image, in ASCII order,
// so all this routine does is just set the coordinates for the character
// and use SDL to blit out.
void drawchar(char ch, int x, int y)
{
  SDL_Rect src, dst;
  src.w = 14;
  src.h = 24;
  src.x = 0;
  src.y = (ch - 32) * 24;
  dst.w = 14;
  dst.h = 24;
  dst.x = x;
  dst.y = y;
  SDL_BlitSurface(gFont, &src, gScreen, &dst);
}

// Draw the string. Characters are fixed width, so this is also
// deadly simple.
void drawstring(char * string, int x, int y)
{
  while (*string)
  {
    drawchar(*string,x,y);
    x += 14;
    string++;
  }
}


// Simplified interface to SDL's fillrect call
void drawrect(int x, int y, int w, int h, int color)
{
  SDL_Rect r;
  r.x = x;
  r.y = y;
  r.w = w;
  r.h = h;
  SDL_FillRect(gScreen, &r, color);
}


// Check whether current mouse position is within a rectangle
int regionhit(int x, int y, int w, int h)
{
  if (uistate.mousex < x ||
    uistate.mousey < y ||
    uistate.mousex >= x + w ||
    uistate.mousey >= y + h)
    return 0;
  return 1;
}

// Simple button IMGUI widget
int button(int id, int x, int y)
{
  // Check whether the button should be hot
  if (regionhit(x, y, 64, 48))
  {
    uistate.hotitem = id;
    if (uistate.activeitem == 0 && uistate.mousedown)
      uistate.activeitem = id;
  }

  // If no widget has keyboard focus, take it
  if (uistate.kbditem == 0)
    uistate.kbditem = id;

  // If we have keyboard focus, show it
  if (uistate.kbditem == id)
    drawrect(x-6, y-6, 84, 68, 0xff0000);

  // Render button 
  drawrect(x+8, y+8, 64, 48, 0);
  if (uistate.hotitem == id)
  {
    if (uistate.activeitem == id)
    {
      // Button is both 'hot' and 'active'
      drawrect(x+2, y+2, 64, 48, 0xffffff);
    }
    else
    {
      // Button is merely 'hot'
      drawrect(x, y, 64, 48, 0xffffff);
    }
  }
  else
  {
    // button is not hot, but it may be active    
    drawrect(x, y, 64, 48, 0xaaaaaa);
  }

  // If we have keyboard focus, we'll need to process the keys
  if (uistate.kbditem == id)
  {
    switch (uistate.keyentered)
    {
    case SDLK_TAB:
      // If tab is pressed, lose keyboard focus.
      // Next widget will grab the focus.
      uistate.kbditem = 0;
      // If shift was also pressed, we want to move focus
      // to the previous widget instead.
      if (uistate.keymod & KMOD_SHIFT)
        uistate.kbditem = uistate.lastwidget;
      // Also clear the key so that next widget
      // won't process it
      uistate.keyentered = 0;
      break;
    case SDLK_RETURN:
      // Had keyboard focus, received return,
      // so we'll act as if we were clicked.
      return 1;
    }
  }

  uistate.lastwidget = id;

  // If button is hot and active, but mouse button is not
  // down, the user must have clicked the button.
  if (uistate.mousedown == 0 && 
    uistate.hotitem == id && 
    uistate.activeitem == id)
    return 1;

  // Otherwise, no clicky.
  return 0;
}

// Simple scroll bar IMGUI widget
int slider(int id, int x, int y, int max, int &value)
{
  // Calculate mouse cursor's relative y offset
  int ypos = ((256 - 16) * value) / max;

  // Check for hotness
  if (regionhit(x+8, y+8, 16, 255))
  {
    uistate.hotitem = id;
    if (uistate.activeitem == 0 && uistate.mousedown)
      uistate.activeitem = id;
  }

  // If no widget has keyboard focus, take it
  if (uistate.kbditem == 0)
    uistate.kbditem = id;

  // If we have keyboard focus, show it
  if (uistate.kbditem == id)
    drawrect(x-4, y-4, 40, 280, 0xff0000);

  // Render the scrollbar
  drawrect(x, y, 32, 256+16, 0x777777);
  
  if (uistate.activeitem == id || uistate.hotitem == id)
  {
    drawrect(x+8, y+8 + ypos, 16, 16, 0xffffff);
  }
  else
  {
    drawrect(x+8, y+8 + ypos, 16, 16, 0xaaaaaa);
  }

  // If we have keyboard focus, we'll need to process the keys
  if (uistate.kbditem == id)
  {
    switch (uistate.keyentered)
    {
    case SDLK_TAB:
      // If tab is pressed, lose keyboard focus.
      // Next widget will grab the focus.
      uistate.kbditem = 0;
      // If shift was also pressed, we want to move focus
      // to the previous widget instead.
      if (uistate.keymod & KMOD_SHIFT)
        uistate.kbditem = uistate.lastwidget;
      // Also clear the key so that next widget
      // won't process it
      uistate.keyentered = 0;
      break;
    case SDLK_UP:
      // Slide slider up (if not at zero)
      if (value > 0)
      {
        value--;
        return 1;
      }
      break;
    case SDLK_DOWN:
      // Slide slider down (if not at max)
      if (value < max)
      {
        value++;
        return 1;
      }
      break;
    }
  }

  uistate.lastwidget = id;

  // Update widget value
  if (uistate.activeitem == id)
  {
    int mousepos = uistate.mousey - (y + 8);
    if (mousepos < 0) mousepos = 0;
    if (mousepos > 255) mousepos = 255;
    int v = (mousepos * max) / 255;
    if (v != value)
    {
      value = v;
      return 1;
    }
  }

  return 0;
}

int textfield(int id, int x, int y, char *buffer)
{
  int len = strlen(buffer);
  int changed = 0;

  // Check for hotness
  if (regionhit(x-4, y-4, 30*14+8, 24+8))
  {
    uistate.hotitem = id;
    if (uistate.activeitem == 0 && uistate.mousedown)
      uistate.activeitem = id;
  }

  // If no widget has keyboard focus, take it
  if (uistate.kbditem == 0)
    uistate.kbditem = id;

  // If we have keyboard focus, show it
  if (uistate.kbditem == id)
    drawrect(x-6, y-6, 30*14+12, 24+12, 0xff0000);

  // Render the text field
  if (uistate.activeitem == id || uistate.hotitem == id)
  {
    drawrect(x-4, y-4, 30*14+8, 24+8, 0xaaaaaa);
  }
  else
  {
    drawrect(x-4, y-4, 30*14+8, 24+8, 0x777777);
  }

  drawstring(buffer,x,y);

  // Render cursor if we have keyboard focus
  if (uistate.kbditem == id && (SDL_GetTicks() >> 8) & 1)
    drawstring("_",x + len * 14, y);

  // If we have keyboard focus, we'll need to process the keys
  if (uistate.kbditem == id)
  {
    switch (uistate.keyentered)
    {
    case SDLK_TAB:
      // If tab is pressed, lose keyboard focus.
      // Next widget will grab the focus.
      uistate.kbditem = 0;
      // If shift was also pressed, we want to move focus
      // to the previous widget instead.
      if (uistate.keymod & KMOD_SHIFT)
        uistate.kbditem = uistate.lastwidget;
      // Also clear the key so that next widget
      // won't process it
      uistate.keyentered = 0;
      break;
    case SDLK_BACKSPACE:
      if (len > 0)
      {
        len--;
        buffer[len] = 0;
        changed = 1;
      }
      break;      
    }
    if (uistate.keychar >= 32 && uistate.keychar < 127 && len < 30)
    {
      buffer[len] = uistate.keychar;
      len++;
      buffer[len] = 0;
      changed = 1;
    }
  }

  // If button is hot and active, but mouse button is not
  // down, the user must have clicked the widget; give it 
  // keyboard focus.
  if (uistate.mousedown == 0 && 
    uistate.hotitem == id && 
    uistate.activeitem == id)
    uistate.kbditem = id;

  uistate.lastwidget = id;

  return changed;
}

void imgui_prepare()
{
  uistate.hotitem = 0;
}

void imgui_finish()
{
  if (uistate.mousedown == 0)
  {
    uistate.activeitem = 0;
  }
  else
  {
    if (uistate.activeitem == 0)
      uistate.activeitem = -1;
  }
  // If no widget grabbed tab, clear focus
  if (uistate.keyentered == SDLK_TAB)
    uistate.kbditem = 0;
  // Clear the entered key
  uistate.keyentered = 0;  
  uistate.keychar = 0;
}

// Rendering function
void render()
{   
  static int bgcolor = 0x77;
  static char sometext[80] = "Some text";

  // clear screen
  drawrect(0,0,640,480,bgcolor);

  imgui_prepare();

  button(GEN_ID,50,50);
  
  button(GEN_ID,150,50);
  
  if (button(GEN_ID,50,150))
    bgcolor = (SDL_GetTicks() * 0xc0cac01a) | 0x77;
  
  if (button(GEN_ID,150,150))
    exit(0);

  textfield(GEN_ID,50,250,sometext);

  int slidervalue = bgcolor & 0xff;
  if (slider(GEN_ID, 500, 40, 255, slidervalue))
  {
    bgcolor = (bgcolor & 0xffff00) | slidervalue;
  }

  slidervalue = ((bgcolor >> 10) & 0x3f);
  if (slider(GEN_ID, 550, 40, 63, slidervalue))
  {
    bgcolor = (bgcolor & 0xff00ff) | (slidervalue << 10);
  }

  slidervalue = ((bgcolor >> 20) & 0xf);
  if (slider(GEN_ID, 600, 40, 15, slidervalue))
  {
    bgcolor = (bgcolor & 0x00ffff) | (slidervalue << 20);
  }


  imgui_finish();
  

  // update the screen
    SDL_UpdateRect(gScreen, 0, 0, 640, 480);    

  // don't take all the cpu time
  SDL_Delay(10); 
}


// Entry point
int main(int argc, char *argv[])
{
  // Initialize SDL's subsystems - in this case, only video.
    if (SDL_Init(SDL_INIT_VIDEO) < 0) 
  {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }

  // Register SDL_Quit to be called at exit; makes sure things are
  // cleaned up when we quit.
    atexit(SDL_Quit);
    
  // Attempt to create a 640x480 window with 32bit pixels.
    gScreen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

  // Enable keyboard repeat to make sliders more tolerable
  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
  // Enable keyboard UNICODE processing for the text field.
  SDL_EnableUNICODE(1);

  // If we fail, return error.
    if (gScreen == NULL) 
  {
        fprintf(stderr, "Unable to set up video: %s\n", SDL_GetError());
        exit(1);
    }

  SDL_Surface *temp = SDL_LoadBMP("font14x24.bmp");
  gFont = SDL_ConvertSurface(temp, gScreen->format, SDL_SWSURFACE);
  SDL_FreeSurface(temp);
  
  // Seeing through the black areas in the font may be a good idea..
  SDL_SetColorKey(gFont, SDL_SRCCOLORKEY, 0);  

  // Main loop: loop forever.
    while (1)
    {
    // Render stuff
        render();

    // Poll for events, and handle the ones we care about.
        SDL_Event event;
        while (SDL_PollEvent(&event)) 
        {
            switch (event.type) 
            {
      case SDL_MOUSEMOTION:
        // update mouse position
        uistate.mousex = event.motion.x;
        uistate.mousey = event.motion.y;
        break;
      case SDL_MOUSEBUTTONDOWN:
        // update button down state if left-clicking
        if (event.button.button == 1)
          uistate.mousedown = 1;
        break;
      case SDL_MOUSEBUTTONUP:
        // update button down state if left-clicking
        if (event.button.button == 1)
          uistate.mousedown = 0;
        break;
      case SDL_KEYDOWN:
        // If a key is pressed, report it to the widgets
        uistate.keyentered = event.key.keysym.sym;
        uistate.keymod = event.key.keysym.mod;
        // if key is ASCII, accept it as character input
        if ((event.key.keysym.unicode & 0xFF80) == 0)
          uistate.keychar = event.key.keysym.unicode & 0x7f;        
        break;
            case SDL_KEYUP:                  
        switch (event.key.keysym.sym)
        {
        case SDLK_ESCAPE:
          // If escape is pressed, return (and thus, quit)
          return 0;
        }
                break;
            case SDL_QUIT:
                return(0);
            }
        }
    }
    return 0;
}

 

posted @ 2017-03-29 10:55  夜梦多离殇  阅读(152)  评论(0)    收藏  举报