text: #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>
  #include <math.h>
  #include <iup.h>
  #include <iup_config.h>
  #include <iupgl.h>
  #include <cd.h>
  #include <cdprint.h>
  #include <cdiup.h>
  #include <cdirgb.h>
  #include <im.h>
  #include <im_image.h>
  #include <im_convert.h>
  #include <iupim.h>
  
  #if _MSC_VER < 1800 /* vc12 (2013) */
  #define DEFINE_ROUND
  #endif
  
  #ifdef DEFINE_ROUND
  double round(double x)
  {
    return (int)(x>0 ? x + 0.5 : x - 0.5);
  }
  #endif
  
  
  /********************************** Images *****************************************/
  
  
  Ihandle* load_image_PaintLine(void)
  {
    unsigned char imgdata[] = {
      0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 239, 0, 0, 0, 60, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 227, 0, 0, 0, 8, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 16, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_Pointer(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 162, 180, 203, 255, 162, 180, 203, 84, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 162, 180, 203, 255, 162, 180, 203, 255, 162, 180, 203, 84, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 162, 180, 203, 255, 240, 243, 246, 255, 162, 180, 203, 255, 162, 180, 203, 69, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 162, 180, 203, 255, 255, 255, 255, 255, 241, 244, 247, 255, 161, 179, 202, 255, 161, 179, 202, 57, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 158, 176, 200, 255, 255, 255, 255, 255, 255, 255, 255, 255, 240, 242, 246, 255, 147, 165, 189, 255, 134, 152, 176, 57, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 153, 172, 195, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 227, 231, 236, 255, 129, 147, 171, 255, 115, 134, 158, 48, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 148, 166, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 253, 254, 255, 213, 218, 226, 255, 111, 130, 154, 255, 96, 115, 140, 57, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 141, 159, 183, 255, 254, 255, 255, 255, 252, 253, 254, 255, 250, 251, 253, 255, 247, 248, 251, 255, 243, 246, 250, 255, 206, 213, 223, 255, 91, 110, 136, 255, 73, 92, 118, 48, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 134, 152, 176, 255, 249, 250, 252, 255, 246, 247, 251, 255, 242, 245, 249, 255, 238, 242, 247, 255, 92, 111, 137, 255, 56, 76, 102, 255, 60, 80, 106, 255, 73, 92, 118, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 127, 145, 170, 255, 241, 244, 249, 255, 205, 212, 221, 255, 88, 108, 133, 255, 229, 234, 243, 255, 105, 124, 148, 255, 105, 124, 148, 83, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 119, 138, 163, 255, 203, 209, 220, 255, 63, 83, 109, 255, 102, 121, 145, 255, 197, 206, 221, 255, 187, 197, 214, 255, 89, 108, 133, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 112, 131, 156, 255, 82, 101, 127, 255, 55, 75, 101, 81, 102, 121, 145, 123, 102, 121, 145, 255, 206, 215, 233, 255, 79, 99, 124, 255, 79, 99, 124, 45, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 105, 124, 150, 255, 255, 255, 255, 0, 255, 255, 255, 0, 102, 121, 145, 18, 95, 115, 140, 255, 190, 202, 223, 255, 152, 167, 189, 255, 67, 87, 112, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 95, 115, 140, 150, 84, 104, 129, 255, 164, 178, 202, 255, 58, 78, 104, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 95, 115, 140, 6, 70, 90, 116, 255, 59, 79, 105, 255, 55, 75, 101, 87, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintPencil(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 194, 126, 104, 73, 173, 108, 94, 255, 173, 108, 94, 255, 188, 121, 101, 48, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 173, 108, 94, 255, 235, 159, 129, 255, 208, 118, 94, 255, 173, 108, 94, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 187, 176, 125, 255, 172, 184, 202, 255, 209, 133, 115, 255, 173, 108, 94, 255, 144, 53, 53, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 185, 172, 115, 255, 238, 224, 140, 255, 217, 196, 108, 255, 134, 134, 125, 255, 144, 53, 53, 255, 131, 57, 47, 78, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 183, 166, 101, 255, 238, 224, 140, 255, 215, 191, 98, 255, 178, 154, 73, 255, 22, 18, 14, 255, 102, 85, 40, 48, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 185, 172, 115, 255, 238, 224, 140, 255, 215, 191, 98, 255, 178, 154, 73, 255, 22, 18, 14, 255, 117, 98, 45, 59, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 183, 166, 101, 255, 238, 224, 140, 255, 215, 191, 98, 255, 178, 154, 73, 255, 22, 18, 14, 255, 117, 98, 45, 59, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 181, 160, 87, 255, 238, 224, 140, 255, 215, 191, 98, 255, 178, 154, 73, 255, 22, 18, 14, 255, 117, 98, 45, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 175, 158, 120, 66, 179, 156, 77, 255, 238, 224, 140, 255, 215, 191, 98, 255, 178, 154, 73, 255, 22, 18, 14, 255, 117, 98, 45, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 157, 163, 255, 199, 183, 136, 255, 226, 206, 116, 255, 178, 154, 73, 255, 22, 18, 14, 255, 82, 68, 37, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 152, 157, 163, 118, 152, 157, 163, 255, 254, 254, 253, 255, 169, 147, 81, 255, 22, 18, 14, 255, 117, 98, 45, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 118, 110, 113, 117, 255, 81, 84, 87, 255, 0, 0, 0, 255, 82, 68, 37, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 224, 0, 0, 0, 118, 81, 84, 87, 104, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintColorPicker(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 1, 1, 1, 85, 0, 0, 1, 192, 0, 0, 0, 192, 0, 0, 0, 85,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 7, 11, 15, 37, 8, 12, 16, 70, 79, 81, 83, 224, 205, 205, 205, 255, 136, 138, 142, 255, 11, 13, 15, 203,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 9, 15, 21, 119, 18, 26, 37, 255, 68, 70, 72, 255, 88, 93, 99, 255, 117, 120, 126, 255, 84, 86, 91, 255, 2, 2, 2, 194,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 15, 21, 30, 31, 23, 34, 49, 235, 49, 56, 65, 255, 70, 72, 72, 255, 54, 56, 58, 255, 21, 22, 22, 199, 0, 0, 0, 85,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 20, 30, 42, 42, 21, 32, 45, 237, 49, 56, 65, 255, 7, 9, 13, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 255, 255, 255, 255, 202, 208, 222, 255, 173, 183, 202, 255, 6, 10, 15, 236, 2, 4, 5, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 255, 255, 255, 255, 202, 208, 222, 255, 143, 156, 181, 255, 68, 88, 114, 255, 1, 1, 3, 33, 0, 0, 0, 111, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 255, 255, 255, 255, 214, 220, 230, 255, 143, 156, 181, 255, 68, 88, 114, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 255, 255, 255, 255, 215, 221, 231, 255, 143, 156, 181, 255, 65, 85, 112, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 255, 255, 255, 255, 216, 220, 231, 255, 143, 156, 181, 255, 65, 85, 112, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 152, 166, 185, 255, 216, 220, 231, 218, 143, 156, 181, 255, 66, 86, 113, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 43, 134, 240, 46, 43, 134, 240, 107, 152, 166, 185, 255, 255, 255, 255, 255, 69, 89, 114, 255, 51, 72, 99, 255, 43, 134, 240, 236, 43, 134, 240, 204, 43, 133, 240, 161, 43, 132, 239, 107, 43, 130, 239, 46, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 43, 133, 239, 170, 43, 133, 240, 255, 87, 105, 130, 255, 79, 97, 123, 255, 43, 134, 240, 255, 43, 134, 240, 255, 43, 135, 240, 255, 43, 134, 240, 255, 43, 134, 240, 255, 43, 134, 240, 255, 43, 133, 239, 170, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 42, 120, 237, 46, 42, 124, 238, 107, 42, 125, 238, 161, 42, 126, 238, 204, 42, 128, 238, 236, 43, 130, 239, 253, 43, 131, 239, 236, 43, 131, 239, 204, 43, 131, 239, 161, 43, 129, 239, 107, 42, 127, 238, 46, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintEllipse(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 20, 0, 0, 0, 84, 0, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 84, 0, 0, 0, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 16, 0, 0, 0, 155, 0, 0, 0, 239, 0, 0, 0, 175, 0, 0, 0, 131, 0, 0, 0, 131, 0, 0, 0, 175, 0, 0, 0, 239, 0, 0, 0, 155, 0, 0, 0, 16, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 215, 0, 0, 0, 143, 0, 0, 0, 16, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 16, 0, 0, 0, 143, 0, 0, 0, 215, 0, 0, 0, 24, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 199, 0, 0, 0, 120, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 120, 0, 0, 0, 199, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 0, 0, 0, 60, 0, 0, 0, 211, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 211, 0, 0, 0, 60, 255, 255, 255, 0,
      255, 255, 255, 0, 0, 0, 0, 120, 0, 0, 0, 139, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 139, 0, 0, 0, 120, 255, 255, 255, 0,
      255, 255, 255, 0, 0, 0, 0, 120, 0, 0, 0, 135, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 135, 0, 0, 0, 120, 255, 255, 255, 0,
      255, 255, 255, 0, 0, 0, 0, 68, 0, 0, 0, 211, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 211, 0, 0, 0, 68, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 199, 0, 0, 0, 120, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 120, 0, 0, 0, 199, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 36, 0, 0, 0, 231, 0, 0, 0, 135, 0, 0, 0, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 12, 0, 0, 0, 135, 0, 0, 0, 231, 0, 0, 0, 36, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 20, 0, 0, 0, 163, 0, 0, 0, 239, 0, 0, 0, 171, 0, 0, 0, 131, 0, 0, 0, 131, 0, 0, 0, 171, 0, 0, 0, 239, 0, 0, 0, 163, 0, 0, 0, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 88, 0, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 88, 0, 0, 0, 24, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintRect(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 254, 0, 0, 0, 247, 0, 0, 0, 239, 0, 0, 0, 247, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintOval(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 135, 0, 0, 0, 211, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 211, 0, 0, 0, 135, 0, 0, 0, 24, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 80, 0, 0, 0, 239, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 239, 0, 0, 0, 80, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 48, 0, 0, 0, 251, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 251, 0, 0, 0, 48, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 183, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 183, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 247, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 247, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 247, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 247, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 183, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 183, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 56, 0, 0, 0, 251, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 251, 0, 0, 0, 56, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 84, 0, 0, 0, 243, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 243, 0, 0, 0, 84, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 139, 0, 0, 0, 211, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 211, 0, 0, 0, 139, 0, 0, 0, 24, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintBox(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 254, 0, 0, 0, 247, 0, 0, 0, 239, 0, 0, 0, 247, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintZoomGrid(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 110, 155, 223, 255, 255, 255, 255, 0, 255, 255, 255, 0, 106, 151, 219, 255, 255, 255, 255, 0, 255, 255, 255, 0, 95, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 129, 201, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 110, 155, 223, 255, 255, 255, 255, 0, 255, 255, 255, 0, 102, 147, 217, 255, 255, 255, 255, 0, 255, 255, 255, 0, 92, 137, 207, 255, 255, 255, 255, 0, 255, 255, 255, 0, 80, 125, 197, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 110, 155, 223, 255, 110, 155, 223, 255, 107, 152, 222, 255, 104, 151, 219, 255, 103, 148, 216, 255, 100, 145, 213, 255, 97, 142, 210, 255, 93, 138, 206, 255, 88, 133, 203, 255, 84, 129, 201, 255, 80, 125, 197, 255, 76, 121, 193, 255, 72, 117, 189, 255, 68, 113, 183, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 106, 149, 219, 255, 255, 255, 255, 0, 255, 255, 255, 0, 97, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 131, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 103, 148, 216, 255, 255, 255, 255, 0, 255, 255, 255, 0, 92, 137, 207, 255, 255, 255, 255, 0, 255, 255, 255, 0, 81, 125, 196, 255, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 104, 151, 219, 255, 104, 148, 216, 255, 100, 145, 213, 255, 97, 142, 210, 255, 92, 137, 207, 255, 88, 135, 203, 255, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 193, 255, 70, 117, 189, 255, 68, 112, 183, 255, 62, 109, 181, 255, 60, 105, 177, 255, 57, 102, 174, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 97, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 129, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 105, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 93, 138, 206, 255, 255, 255, 255, 0, 255, 255, 255, 0, 80, 125, 195, 255, 255, 255, 255, 0, 255, 255, 255, 0, 66, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 56, 103, 173, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 95, 140, 212, 255, 92, 137, 207, 255, 88, 133, 203, 255, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 193, 255, 72, 117, 187, 255, 68, 113, 185, 255, 64, 107, 181, 255, 59, 105, 178, 255, 55, 101, 174, 255, 53, 98, 170, 255, 49, 95, 168, 255, 48, 91, 165, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 84, 131, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 70, 117, 189, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 105, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 49, 95, 168, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 82, 125, 195, 255, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 57, 102, 174, 255, 255, 255, 255, 0, 255, 255, 255, 0, 46, 92, 165, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 191, 255, 72, 117, 189, 255, 66, 113, 185, 255, 64, 109, 181, 255, 60, 105, 177, 255, 55, 102, 174, 255, 52, 98, 171, 255, 49, 95, 168, 255, 46, 91, 166, 255, 44, 90, 163, 255, 42, 88, 161, 255, 42, 88, 161, 255, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 107, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 50, 95, 167, 255, 255, 255, 255, 0, 255, 255, 255, 0, 42, 88, 161, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 56, 101, 173, 255, 255, 255, 255, 0, 255, 255, 255, 0, 46, 92, 165, 255, 255, 255, 255, 0, 255, 255, 255, 0, 42, 88, 161, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintFill(void)
  {
    unsigned char imgdata[] = {
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 53, 53, 86, 59, 59, 59, 111, 108, 108, 108, 82, 127, 127, 127, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 54, 54, 122, 72, 72, 72, 7, 119, 122, 124, 117, 124, 124, 130, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 76, 154, 144, 166, 188, 23, 158, 169, 181, 191, 144, 151, 159, 194, 134, 147, 174, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 126, 129, 197, 141, 160, 183, 179, 212, 219, 225, 254, 157, 162, 166, 254, 163, 180, 200, 168, 159, 175, 191, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 141, 158, 45, 130, 143, 155, 245, 218, 225, 232, 250, 222, 232, 239, 255, 136, 139, 142, 255, 205, 217, 227, 252, 148, 167, 189, 163, 155, 155, 184, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 148, 170, 24, 134, 155, 174, 172, 213, 220, 227, 254, 218, 233, 243, 255, 197, 207, 217, 255, 149, 149, 150, 255, 232, 241, 245, 255, 179, 196, 213, 252, 129, 147, 172, 164, 75, 103, 144, 37, 17, 51, 102, 15, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 134, 147, 174, 19, 122, 146, 168, 179, 216, 223, 228, 252, 217, 231, 242, 255, 213, 227, 238, 255, 159, 162, 164, 255, 128, 129, 128, 255, 228, 235, 239, 255, 171, 197, 218, 255, 136, 162, 190, 253, 87, 116, 156, 227, 37, 75, 150, 183, 0, 31, 107, 57, 0, 0, 0, 0,
      0, 0, 0, 0, 120, 134, 161, 19, 126, 147, 168, 157, 209, 217, 225, 245, 217, 231, 241, 255, 203, 217, 232, 255, 242, 244, 245, 255, 192, 192, 191, 255, 164, 166, 169, 255, 202, 213, 223, 255, 158, 176, 194, 255, 126, 154, 184, 255, 103, 134, 168, 255, 76, 110, 169, 255, 49, 93, 175, 201, 37, 66, 132, 27,
      122, 132, 160, 27, 102, 124, 149, 172, 194, 209, 220, 241, 213, 228, 239, 246, 204, 218, 232, 249, 241, 242, 244, 255, 247, 245, 245, 255, 243, 244, 243, 255, 222, 228, 234, 255, 192, 203, 214, 255, 159, 172, 185, 255, 138, 152, 168, 255, 84, 116, 151, 248, 74, 104, 158, 246, 83, 129, 213, 243, 77, 108, 169, 92,
      125, 134, 152, 55, 111, 131, 154, 211, 189, 201, 214, 255, 214, 223, 234, 254, 238, 240, 243, 236, 248, 246, 245, 241, 242, 243, 243, 254, 221, 228, 234, 255, 192, 203, 214, 255, 165, 178, 192, 255, 142, 155, 169, 255, 98, 117, 137, 243, 77, 94, 120, 121, 46, 82, 158, 171, 87, 131, 209, 247, 85, 114, 171, 122,
      0, 255, 255, 1, 134, 140, 167, 38, 137, 155, 179, 206, 218, 223, 230, 254, 244, 242, 243, 252, 242, 244, 243, 239, 220, 228, 234, 252, 192, 202, 214, 255, 164, 176, 190, 255, 140, 154, 168, 255, 92, 112, 132, 243, 75, 91, 114, 111, 102, 102, 153, 5, 29, 61, 136, 140, 68, 109, 192, 244, 84, 113, 170, 94,
      0, 0, 0, 0, 0, 0, 255, 1, 157, 173, 195, 47, 148, 166, 191, 205, 204, 210, 220, 248, 227, 231, 235, 253, 193, 204, 216, 255, 163, 175, 189, 255, 138, 151, 166, 255, 95, 113, 134, 242, 74, 88, 113, 110, 95, 127, 127, 8, 0, 0, 0, 0, 35, 66, 135, 145, 72, 109, 182, 239, 91, 120, 178, 53,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 142, 165, 34, 103, 124, 151, 197, 158, 172, 187, 252, 164, 176, 189, 255, 134, 148, 162, 254, 96, 113, 133, 245, 75, 87, 110, 122, 102, 102, 102, 5, 0, 0, 0, 0, 0, 0, 0, 0, 60, 91, 151, 173, 84, 115, 173, 195, 98, 117, 176, 13,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 110, 119, 30, 73, 96, 120, 204, 107, 126, 144, 255, 106, 123, 141, 255, 102, 115, 135, 152, 139, 150, 162, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 92, 154, 173, 85, 115, 173, 119, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 82, 115, 31, 49, 79, 109, 212, 92, 110, 134, 169, 143, 159, 175, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 93, 154, 163, 63, 89, 153, 20, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 118, 140, 58, 85, 106, 148, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 92, 154, 33, 0, 0, 0, 0, 0, 0, 0, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  Ihandle* load_image_PaintText(void)
  {
    unsigned char imgdata[] = {
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 36, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 96, 0, 0, 0, 72, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 96, 0, 0, 0, 255, 0, 0, 0, 203, 0, 0, 0, 124, 0, 0, 0, 135, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 215, 0, 0, 0, 96, 0, 0, 0, 131, 0, 0, 0, 243, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 96, 0, 0, 0, 163, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 44, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 96, 0, 0, 0, 48, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 116, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 64, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 191, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 96, 0, 0, 0, 187, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 243, 0, 0, 0, 116, 0, 0, 0, 48, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
      255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };
  
    Ihandle* image = IupImageRGBA(16, 16, imgdata);
    return image;
  }
  
  
  /********************************** Utilities *****************************************/
  
  
  const char* str_filetitle(const char *filename)
  {
    /* Start at the last character */
    int len = (int)strlen(filename);
    int offset = len - 1;
    while (offset != 0)
    {
      if (filename[offset] == '\\' || filename[offset] == '/')
      {
        offset++;
        break;
      }
      offset--;
    }
    return filename + offset;
  }
  
  const char* str_fileext(const char *filename)
  {
    /* Start at the last character */
    int len = (int)strlen(filename);
    int offset = len - 1;
    while (offset != 0)
    {
      if (filename[offset] == '\\' || filename[offset] == '/')
        break;
  
      if (filename[offset] == '.')
      {
        offset++;
        return filename + offset;
      }
      offset--;
    }
    return NULL;
  }
  
  int str_compare(const char *l, const char *r, int casesensitive)
  {
    if (!l || !r)
      return 0;
  
    while (*l && *r)
    {
      int diff;
      char l_char = *l,
        r_char = *r;
  
      /* compute the difference of both characters */
      if (casesensitive)
        diff = l_char - r_char;
      else
        diff = tolower((int)l_char) - tolower((int)r_char);
  
      /* if they differ we have a result */
      if (diff != 0)
        return 0;
  
      /* otherwise process the next characters */
      ++l;
      ++r;
    }
  
    /* check also for terminator */
    if (*l == *r)
      return 1;
  
    if (*r == 0)
      return 1;  /* if second string is at terminator, then it is partially equal */
  
    return 0;
  }
  
  void show_error(const char* message, int is_error)
  {
    Ihandle* dlg = IupMessageDlg();
    IupSetStrAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG"));
    IupSetAttribute(dlg, "DIALOGTYPE", is_error ? "ERROR" : "WARNING");
    IupSetAttribute(dlg, "BUTTONS", "OK");
    IupSetStrAttribute(dlg, "TITLE", is_error ? "Error" : "Warning");
    IupSetStrAttribute(dlg, "VALUE", message);
    IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
    IupDestroy(dlg);
  }
  
  void show_file_error(int error)
  {
    switch (error)
    {
    case IM_ERR_OPEN:
      show_error("Error Opening File.",  1);
      break;
    case IM_ERR_MEM:
      show_error("Insufficient memory.",  1);
      break;
    case IM_ERR_ACCESS:
      show_error("Error Accessing File.",  1);
      break;
    case IM_ERR_DATA:
      show_error("Image type not Supported.",  1);
      break;
    case IM_ERR_FORMAT:
      show_error("Invalid Format.",  1);
      break;
    case IM_ERR_COMPRESS:
      show_error("Invalid or unsupported compression.",  1);
      break;
    default:
      show_error("Unknown Error.",  1);
    }
  }
  
  imImage* read_file(const char* filename)
  {
    int error;
    imImage* image = imFileImageLoadBitmap(filename, 0, &error);
    if (error) 
      show_file_error(error);
    return image;
  }
  
  int write_file(const char* filename, const imImage* image)
  {
    const char* format = imImageGetAttribString(image, "FileFormat");
    int error = imFileImageSave(filename, format, image);
    if (error)
    {
      show_file_error(error);
      return 0;
    }
    return 1;
  }
  
  /* extracted from the SCROLLBAR attribute documentation */
  void scroll_update(Ihandle* ih, int view_width, int view_height)
  {
    /* view_width and view_height is the virtual space size */
    /* here we assume XMIN=0, XMAX=1, YMIN=0, YMAX=1 */
    int elem_width, elem_height;
    int canvas_width, canvas_height;
    int scrollbar_size = IupGetInt(NULL, "SCROLLBARSIZE");
    int border = IupGetInt(ih, "BORDER");
  
    IupGetIntInt(ih, "RASTERSIZE", &elem_width, &elem_height);
  
    /* if view is greater than canvas in one direction,
    then it has scrollbars,
    but this affects the opposite direction */
    elem_width -= 2 * border;  /* remove BORDER (always size=1) */
    elem_height -= 2 * border;
    canvas_width = elem_width;
    canvas_height = elem_height;
    if (view_width > elem_width)  /* check for horizontal scrollbar */
      canvas_height -= scrollbar_size;  /* affect vertical size */
    if (view_height > elem_height)
      canvas_width -= scrollbar_size;
    if (view_width <= elem_width && view_width > canvas_width)  /* check if still has horizontal scrollbar */
      canvas_height -= scrollbar_size;
    if (view_height <= elem_height && view_height > canvas_height)
      canvas_width -= scrollbar_size;
    if (canvas_width < 0) canvas_width = 0;
    if (canvas_height < 0) canvas_height = 0;
  
    IupSetFloat(ih, "DX", (float)canvas_width / (float)view_width);
    IupSetFloat(ih, "DY", (float)canvas_height / (float)view_height);
  }
  
  void scroll_calc_center(Ihandle* ih, float *x, float *y)
  {
    *x = IupGetFloat(ih, "POSX") + IupGetFloat(ih, "DX") / 2.0f;
    *y = IupGetFloat(ih, "POSY") + IupGetFloat(ih, "DY") / 2.0f;
  }
  
  void scroll_center(Ihandle* ih, float old_center_x, float old_center_y)
  {
    /* always update the scroll position
       keeping it proportional to the old position
       relative to the center of the ih. */
  
    float dx = IupGetFloat(ih, "DX");
    float dy = IupGetFloat(ih, "DY");
  
    float posx = old_center_x - dx / 2.0f;
    float posy = old_center_y - dy / 2.0f;
  
    if (posx < 0) posx = 0;
    if (posx > 1 - dx) posx = 1 - dx;
  
    if (posy < 0) posy = 0;
    if (posy > 1 - dy) posy = 1 - dy;
  
    IupSetFloat(ih, "POSX", posx);
    IupSetFloat(ih, "POSY", posy);
  }
  
  void scroll_move(Ihandle* ih, int canvas_width, int canvas_height, int move_x, int move_y, int view_width, int view_height)
  {
    float posy = 0;
    float posx = 0;
  
    if (move_x == 0 && move_y == 0)
      return;
  
    if (canvas_height < view_height)
    {
      posy = IupGetFloat(ih, "POSY");
      posy -= (float)move_y / (float)view_height;
    }
  
    if (canvas_width < view_width)
    {
      posx = IupGetFloat(ih, "POSX");
      posx -= (float)move_x / (float)view_width;
    }
  
    if (posx != 0 || posy != 0)
    {
      IupSetFloat(ih, "POSX", posx);
      IupSetFloat(ih, "POSY", posy);
      IupUpdate(ih);
    }
  }
  
  void zoom_update(Ihandle* ih, double zoom_index)
  {
    Ihandle* zoom_lbl = IupGetDialogChild(ih, "ZOOMLABEL");
    Ihandle* canvas = IupGetDialogChild(ih, "CANVAS");
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    double zoom_factor = pow(2, zoom_index);
    IupSetStrf(zoom_lbl, "TITLE", "%.0f%%", floor(zoom_factor * 100));
    if (image)
    {
      float old_center_x, old_center_y;
      int view_width = (int)(zoom_factor * image->width);
      int view_height = (int)(zoom_factor * image->height);
  
      scroll_calc_center(canvas, &old_center_x, &old_center_y);
  
      scroll_update(canvas, view_width, view_height);
  
      scroll_center(canvas, old_center_x, old_center_y);
    }
    IupUpdate(canvas);
  }
  
  typedef struct _xyStack
  {
    int x, y;
    struct _xyStack* next;
  } xyStack;
  
  xyStack* xy_stack_push(xyStack* q, int x, int y)
  {
    xyStack* new_q = malloc(sizeof(xyStack));
    new_q->x = x;
    new_q->y = y;
    new_q->next = q;
    return new_q;
  }
  
  xyStack* xy_stack_pop(xyStack* q)
  {
    xyStack* next_q = q->next;
    free(q);
    return next_q;
  }
  
  int color_is_similar(long color1, long color2, int tol)
  {
    int diff_r = cdRed(color1) - cdRed(color2);
    int diff_g = cdGreen(color1) - cdGreen(color2);
    int diff_b = cdBlue(color1) - cdBlue(color2);
    int sqr_dist = diff_r*diff_r + diff_g*diff_g + diff_b*diff_b;
    /* max value = 255*255*3 = 195075 */
    /* sqrt(195075)=441 */
    if (sqr_dist < tol)
      return 1;
    else
      return 0;
  }
  
  void image_flood_fill(imImage* image, int start_x, int start_y, long replace_color, double tol_percent)
  {
    unsigned char** data = (unsigned char**)image->data;
    unsigned char *r = data[0], *g = data[1], *b = data[2];
    int offset, tol, cur_x, cur_y;
    long target_color, color;
    xyStack* q = NULL;
  
    offset = start_y * image->width + start_x;
    target_color = cdEncodeColor(r[offset], g[offset], b[offset]);
  
    if (target_color == replace_color)
      return;
  
    tol = (int)(441 * tol_percent) / 100;
    tol = tol*tol;  /* this is too high */
    tol = tol / 50;  /* empirical reduce. TODO: What is the best formula? */
  
    /* very simple 4 neighbors stack based flood fill */
  
    /* a color in the xy_stack is always similar to the target color,
    and it was already replaced */
    q = xy_stack_push(q, start_x, start_y);
    cdDecodeColor(replace_color, r + offset, g + offset, b + offset);
  
    while (q)
    {
      cur_x = q->x;
      cur_y = q->y;
      q = xy_stack_pop(q);
  
      /* right */
      if (cur_x < image->width - 1)
      {
        offset = cur_y * image->width + cur_x+1;
        color = cdEncodeColor(r[offset], g[offset], b[offset]);
        if (color != replace_color && color_is_similar(color, target_color, tol))
        {
          q = xy_stack_push(q, cur_x+1, cur_y);
          cdDecodeColor(replace_color, r + offset, g + offset, b + offset);
        }
      }
  
      /* left */
      if (cur_x > 0)
      {
        offset = cur_y * image->width + cur_x-1;
        color = cdEncodeColor(r[offset], g[offset], b[offset]);
        if (color != replace_color && color_is_similar(color, target_color, tol))
        {
          q = xy_stack_push(q, cur_x-1, cur_y);
          cdDecodeColor(replace_color, r + offset, g + offset, b + offset);
        }
      }
  
      /* top */
      if (cur_y < image->height - 1)
      {
        offset = (cur_y+1) * image->width + cur_x;
        color = cdEncodeColor(r[offset], g[offset], b[offset]);
        if (color != replace_color && color_is_similar(color, target_color, tol))
        {
          q = xy_stack_push(q, cur_x, cur_y+1);
          cdDecodeColor(replace_color, r + offset, g + offset, b + offset);
        }
      }
  
      /* bottom */
      if (cur_y > 0)
      {
        offset = (cur_y-1) * image->width + cur_x;
        color = cdEncodeColor(r[offset], g[offset], b[offset]);
        if (color != replace_color && color_is_similar(color, target_color, tol))
        {
          q = xy_stack_push(q, cur_x, cur_y-1);
          cdDecodeColor(replace_color, r + offset, g + offset, b + offset);
        }
      }
    }
  }
  
  void image_fill_white(imImage* image)
  {
    unsigned char** data = (unsigned char**)image->data;
    int x, y, offset;
  
    for (y = 0; y < image->height; y++)
    {
      for (x = 0; x < image->width; x++)
      {
        offset = y * image->width + x;
        data[0][offset] = 255;
        data[1][offset] = 255;
        data[2][offset] = 255;
      }
    }
  }
  
  void set_new_image(Ihandle* canvas, imImage* image, const char* filename, int dirty)
  {
    imImage* old_image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    Ihandle* size_lbl = IupGetDialogChild(canvas, "SIZELABEL");
    Ihandle* zoom_val = IupGetDialogChild(canvas, "ZOOMVAL");
  
    if (filename)
    {
      IupSetStrAttribute(canvas, "FILENAME", filename);
      IupSetfAttribute(IupGetDialog(canvas), "TITLE", "%s - Simple Paint", str_filetitle(filename));
    }
    else
    {
      IupSetAttribute(canvas, "FILENAME", NULL);
      IupSetAttribute(IupGetDialog(canvas), "TITLE", "Untitled - Simple Paint");
    }
  
    /* we are going to support only RGB images with no alpha */
    imImageRemoveAlpha(image);
    if (image->color_space != IM_RGB)
    {
      imImage* new_image = imImageCreateBased(image, -1, -1, IM_RGB, -1);
      imConvertColorSpace(image, new_image);
      imImageDestroy(image);
  
      image = new_image;
    }
  
    /* default file format */
    const char* format = imImageGetAttribString(image, "FileFormat");
    if (!format)
      imImageSetAttribString(image, "FileFormat", "JPEG");
  
    IupSetAttribute(canvas, "DIRTY", dirty ? "Yes" : "No");
    IupSetAttribute(canvas, "IMAGE", (char*)image);
  
    IupSetfAttribute(size_lbl, "TITLE", "%d x %d px", image->width, image->height);
  
    if (old_image)
      imImageDestroy(old_image);
  
    IupSetDouble(zoom_val, "VALUE", 0);
    zoom_update(canvas, 0);
  }
  
  void check_new_file(Ihandle* dlg)
  {
    Ihandle* canvas = IupGetDialogChild(dlg, "CANVAS");
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (!image)
    {
      Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
      int width = IupConfigGetVariableIntDef(config, "NewImage", "Width", 640);
      int height = IupConfigGetVariableIntDef(config, "NewImage", "Height", 480);
  
      image = imImageCreate(width, height, IM_RGB, IM_BYTE);
      image_fill_white(image);
  
      set_new_image(canvas, image, NULL, 0);
    }
  }
  
  void open_file(Ihandle* ih, const char* filename)
  {
    imImage* image = read_file(filename);
    if (image)
    {
      Ihandle* canvas = IupGetDialogChild(ih, "CANVAS");
      Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
  
      set_new_image(canvas, image, filename, 0);
  
      IupConfigRecentUpdate(config, filename);
    }
  }
  
  void save_file(Ihandle* canvas)
  {
    char* filename = IupGetAttribute(canvas, "FILENAME");
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (write_file(filename, image))
      IupSetAttribute(canvas, "DIRTY", "NO");
  }
  
  void set_file_format(imImage* image, const char* filename)
  {
    const char* ext = str_fileext(filename);
    const char* format = "JPEG";
    if (str_compare(ext, "jpg", 0) || str_compare(ext, "jpeg", 0))
      format = "JPEG";
    else if (str_compare(ext, "bmp", 0))
      format = "BMP";
    else if (str_compare(ext, "png", 0))
      format = "PNG";
    else if (str_compare(ext, "tga", 0))
      format = "TGA";
    else if (str_compare(ext, "tif", 0) || str_compare(ext, "tiff", 0))
      format = "TIFF";
    imImageSetAttribString(image, "FileFormat", format);
  }
  
  void saveas_file(Ihandle* canvas, const char* filename)
  {
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
  
    set_file_format(image, filename);
  
    if (write_file(filename, image))
    {
      Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
    
      IupSetfAttribute(IupGetDialog(canvas), "TITLE", "%s - Simple Paint", str_filetitle(filename));
      IupSetStrAttribute(canvas, "FILENAME", filename);
      IupSetAttribute(canvas, "DIRTY", "NO");
  
      IupConfigRecentUpdate(config, filename);
    }
  }
  
  int save_check(Ihandle* ih)
  {
    Ihandle* canvas = IupGetDialogChild(ih, "CANVAS");
    if (IupGetInt(canvas, "DIRTY"))
    {
      switch (IupAlarm("Warning", "File not saved! Save it now?", "Yes", "No", "Cancel"))
      {
      case 1:  /* save the changes and continue */
        save_file(canvas);
        break;
      case 2:  /* ignore the changes and continue */
        break;
      case 3:  /* cancel */
        return 0;  
      }
    }
    return 1;
  }
  
  void toggle_bar_visibility(Ihandle* item, Ihandle* ih)
  {
    if (IupGetInt(item, "VALUE"))
    {
      IupSetAttribute(ih, "FLOATING", "YES");
      IupSetAttribute(ih, "VISIBLE", "NO");
      IupSetAttribute(item, "VALUE", "OFF");
    }
    else
    {
      IupSetAttribute(ih, "FLOATING", "NO");
      IupSetAttribute(ih, "VISIBLE", "YES");
      IupSetAttribute(item, "VALUE", "ON");
    }
  
    IupRefresh(ih);  /* refresh the dialog layout */
  }
  
  int select_file(Ihandle* parent_dlg, int is_open)
  {
    Ihandle* config = (Ihandle*)IupGetAttribute(parent_dlg, "CONFIG");
    Ihandle* canvas = IupGetDialogChild(parent_dlg, "CANVAS");
    const char* dir = IupConfigGetVariableStr(config, "MainWindow", "LastDirectory");
  
    Ihandle* filedlg = IupFileDlg();
    if (is_open)
      IupSetAttribute(filedlg, "DIALOGTYPE", "OPEN");
    else
    {
      IupSetAttribute(filedlg, "DIALOGTYPE", "SAVE");
      IupSetStrAttribute(filedlg, "FILE", IupGetAttribute(canvas, "FILENAME"));
    }
    IupSetAttribute(filedlg, "EXTFILTER", "Image Files|*.bmp;*.jpg;*.png;*.tif;*.tga|All Files|*.*|");
    IupSetStrAttribute(filedlg, "DIRECTORY", dir);
    IupSetAttributeHandle(filedlg, "PARENTDIALOG", parent_dlg);
  
    IupPopup(filedlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
    if (IupGetInt(filedlg, "STATUS") != -1)
    {
      char* filename = IupGetAttribute(filedlg, "VALUE");
      if (is_open)
        open_file(parent_dlg, filename);
      else
        saveas_file(canvas, filename);
  
      dir = IupGetAttribute(filedlg, "DIRECTORY");
      IupConfigSetVariableStr(config, "MainWindow", "LastDirectory", dir);
    }
  
    IupDestroy(filedlg);
    return IUP_DEFAULT;
  }
  
  void view_fit_rect(int canvas_width, int canvas_height, int image_width, int image_height, int *view_width, int *view_height)
  {
    *view_width = canvas_width;
    *view_height = (canvas_width * image_height) / image_width;
  
    if (*view_height > canvas_height)
    {
      *view_height = canvas_height;
      *view_width = (canvas_height * image_width) / image_height;
    }
  }
  
  double view_zoom_rect(Ihandle* ih, int image_width, int image_height, int *_x, int *_y, int *_view_width, int *_view_height)
  {
    int x, y, canvas_width, canvas_height;
    int view_width, view_height;
    Ihandle* zoom_val = IupGetDialogChild(ih, "ZOOMVAL");
    double zoom_index = IupGetDouble(zoom_val, "VALUE");
    double zoom_factor = pow(2, zoom_index);
  
    float posy = IupGetFloat(ih, "POSY");
    float posx = IupGetFloat(ih, "POSX");
  
    IupGetIntInt(ih, "DRAWSIZE", &canvas_width, &canvas_height);
  
    view_width = (int)(zoom_factor * image_width);
    view_height = (int)(zoom_factor * image_height);
  
    if (canvas_width < view_width)
      x = (int)floor(-posx*view_width);
    else
      x = (canvas_width - view_width) / 2;
  
    if (canvas_height < view_height)
    {
      /* posy is top-bottom, CD is bottom-top.
      invert posy reference (YMAX-DY - POSY) */
      float dy = IupGetFloat(ih, "DY");
      posy = 1.0f - dy - posy;
      y = (int)floor(-posy*view_height);
    }
    else
      y = (canvas_height - view_height) / 2;
  
    *_x = x;
    *_y = y;
    *_view_width = view_width;
    *_view_height = view_height;
  
    return zoom_factor;
  }
  
  void view_zoom_offset(int view_x, int view_y, int image_width, int image_height, double zoom_factor, int *x, int *y)
  {
    *x -= view_x;
    *y -= view_y;
  
    *x = (int)(*x / zoom_factor);
    *y = (int)(*y / zoom_factor);
  
    if (*x < 0) *x = 0;
    if (*y < 0) *y = 0;
    if (*x > image_width - 1) *x = image_width - 1;
    if (*y > image_height - 1) *y = image_height - 1;
  }
  
  int tool_get_text_enter_cb(void)
  {
    return IUP_CLOSE;
  }
  
  void tool_get_text(Ihandle* toolbox)
  {
    Ihandle *text, *dlg;
  
    char* value = IupGetAttribute(toolbox, "TOOLTEXT");
    char* font = IupGetAttribute(toolbox, "TOOLFONT");
  
    text = IupText(NULL);
    IupSetAttribute(text, "EXPAND", "YES");
    IupSetStrAttribute(text, "VALUE", value);
    IupSetStrAttribute(text, "FONT", font);
    IupSetAttribute(text, "VISIBLECOLUMNS", "20");
  
    dlg = IupDialog(text);
  
    IupSetStrAttribute(dlg, "TITLE", "Enter Text:");
    IupSetAttribute(dlg, "MINBOX", "NO");
    IupSetAttribute(dlg, "MAXBOX", "NO");
    IupSetCallback(dlg, "K_CR", (Icallback)tool_get_text_enter_cb);
    IupSetAttributeHandle(dlg, "PARENTDIALOG", toolbox);
  
    IupPopup(dlg, IUP_MOUSEPOS, IUP_MOUSEPOS);
  
    value = IupGetAttribute(text, "VALUE");
    IupSetStrAttribute(toolbox, "TOOLTEXT", value);
  
    IupDestroy(dlg);
  }
  
  
  
  
  
  /********************************** Callbacks *****************************************/
  
  
  int canvas_action_cb(Ihandle* canvas)
  {
    unsigned int ri, gi, bi;
    imImage* image;
    cdCanvas* cd_canvas = (cdCanvas*)IupGetAttribute(canvas, "cdCanvas");
    Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
    const char* background = IupConfigGetVariableStrDef(config, "Canvas", "Background", "208 208 208");
  
    cdCanvasActivate(cd_canvas);
  
    /* draw the background */
    sscanf(background, "%u %u %u", &ri, &gi, &bi);
    cdCanvasBackground(cd_canvas, cdEncodeColor((unsigned char)ri, (unsigned char)gi, (unsigned char)bi));
    cdCanvasClear(cd_canvas);
  
    /* draw the image at the center of the canvas */
    image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (image)
    {
      int view_x, view_y, view_width, view_height;
      view_zoom_rect(canvas, image->width, image->height, &view_x, &view_y, &view_width, &view_height);
  
      /* black line around the image */
      cdCanvasForeground(cd_canvas, CD_BLACK);
      cdCanvasLineWidth(cd_canvas, 1);
      cdCanvasLineStyle(cd_canvas, CD_CONTINUOUS);
      cdCanvasRect(cd_canvas, view_x - 1, view_x + view_width, view_y - 1, view_y + view_height);
  
      imcdCanvasPutImage(cd_canvas, image, view_x, view_y, view_width, view_height, 0, 0, 0, 0);
  
      if (IupConfigGetVariableInt(config, "Canvas", "ZoomGrid"))
      {
        Ihandle* zoom_val = IupGetDialogChild(canvas, "ZOOMVAL");
        double zoom_index = IupGetDouble(zoom_val, "VALUE");
        if (zoom_index > 1)
        {
          int ix, iy;
          double zoom_factor = pow(2, zoom_index);
  
          cdCanvasForeground(cd_canvas, CD_GRAY);
  
          for (ix = 0; ix < image->width; ix++)
          {
            int gx = (int)(ix * zoom_factor);
            cdCanvasLine(cd_canvas, gx + view_x, view_y, gx + view_x, view_y + view_height);
          }
          for (iy = 0; iy < image->height; iy++)
          {
            int gy = (int)(iy * zoom_factor);
            cdCanvasLine(cd_canvas, view_x, gy + view_y, view_x + view_width, gy + view_y);
          }
        }
      }
  
      if (IupGetAttribute(canvas, "OVERLAY"))
      {
        Ihandle* toolbox = (Ihandle*)IupGetAttribute(canvas, "TOOLBOX");
        int start_x = IupGetInt(canvas, "START_X");
        int start_y = IupGetInt(canvas, "START_Y");
        int end_x = IupGetInt(canvas, "END_X");
        int end_y = IupGetInt(canvas, "END_Y");
        int line_width = IupGetInt(toolbox, "TOOLWIDTH");
        int line_style = IupGetInt(toolbox, "TOOLSTYLE") - 1;
        unsigned char r, g, b;
        IupGetRGB(toolbox, "TOOLCOLOR", &r, &g, &b);
  
        cdCanvasTransformTranslate(cd_canvas, view_x, view_y);
        cdCanvasTransformScale(cd_canvas, (double)view_width / (double)image->width, view_height / (double)image->height);
  
  
        cdCanvasForeground(cd_canvas, cdEncodeColor(r, g, b));
        cdCanvasLineWidth(cd_canvas, line_width);
        if (line_width == 1)
          cdCanvasLineStyle(cd_canvas, line_style);
  
        if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "LINE") == 0)
          cdCanvasLine(cd_canvas, start_x, start_y, end_x, end_y);
        else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "RECT") == 0)
          cdCanvasRect(cd_canvas, start_x, end_x, start_y, end_y);
        else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "BOX") == 0)
          cdCanvasBox(cd_canvas, start_x, end_x, start_y, end_y);
        else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "ELLIPSE") == 0)
          cdCanvasArc(cd_canvas, (end_x + start_x) / 2, (end_y + start_y) / 2, abs(end_x - start_x), abs(end_y - start_y), 0, 360);
        else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "OVAL") == 0)
          cdCanvasSector(cd_canvas, (end_x + start_x) / 2, (end_y + start_y) / 2, abs(end_x - start_x), abs(end_y - start_y), 0, 360);
        else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "TEXT") == 0)
        {
          cdCanvasTextAlignment(cd_canvas, CD_SOUTH_WEST);
          cdCanvasNativeFont(cd_canvas, IupGetAttribute(toolbox, "TOOLFONT"));
          cdCanvasText(cd_canvas, end_x, end_y, IupGetAttribute(toolbox, "TOOLTEXT"));
        }
  
        cdCanvasTransform(cd_canvas, NULL);
      }
    }
  
    cdCanvasFlush(cd_canvas);
    return IUP_DEFAULT;
  }
  
  int canvas_map_cb(Ihandle* canvas)
  {
    cdCanvas* cd_canvas = cdCreateCanvas(CD_IUPDBUFFER, canvas);
    IupSetAttribute(canvas, "cdCanvas", (char*)cd_canvas);
    return IUP_DEFAULT;
  }
  
  int canvas_unmap_cb(Ihandle* canvas)
  {
    cdCanvas* cd_canvas = (cdCanvas*)IupGetAttribute(canvas, "cdCanvas");
    cdKillCanvas(cd_canvas);
    return IUP_DEFAULT;
  }
  
  int zoomout_action_cb(Ihandle* ih)
  {
    Ihandle* zoom_val = IupGetDialogChild(ih, "ZOOMVAL");
    double zoom_index = IupGetDouble(zoom_val, "VALUE");
    zoom_index--;
    if (zoom_index < -6)
      zoom_index = -6;
    IupSetDouble(zoom_val, "VALUE", round(zoom_index));  /* fixed increments when using buttons */
  
    zoom_update(ih, zoom_index);
    return IUP_DEFAULT;
  }
  
  int zoomin_action_cb(Ihandle* ih)
  {
    Ihandle* zoom_val = IupGetDialogChild(ih, "ZOOMVAL");
    double zoom_index = IupGetDouble(zoom_val, "VALUE");
    zoom_index++;
    if (zoom_index > 6)
      zoom_index = 6;
    IupSetDouble(zoom_val, "VALUE", round(zoom_index));  /* fixed increments when using buttons */
  
    zoom_update(ih, zoom_index);
    return IUP_DEFAULT;
  }
  
  int actualsize_action_cb(Ihandle* ih)
  {
    Ihandle* zoom_val = IupGetDialogChild(ih, "ZOOMVAL");
    IupSetDouble(zoom_val, "VALUE", 0);
    zoom_update(ih, 0);
    return IUP_DEFAULT;
  }
  
  int canvas_resize_cb(Ihandle* canvas)
  {
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (image)
    {
      Ihandle* zoom_val = IupGetDialogChild(canvas, "ZOOMVAL");
      double zoom_index = IupGetDouble(zoom_val, "VALUE");
      double zoom_factor = pow(2, zoom_index);
      float old_center_x, old_center_y;
  
      int view_width = (int)(zoom_factor * image->width);
      int view_height = (int)(zoom_factor * image->height);
  
      scroll_calc_center(canvas, &old_center_x, &old_center_y);
  
      scroll_update(canvas, view_width, view_height);
  
      scroll_center(canvas, old_center_x, old_center_y);
    }
    return IUP_DEFAULT;
  }
  
  int canvas_wheel_cb(Ihandle* canvas, float delta)
  {
    if (IupGetInt(NULL, "CONTROLKEY"))
    {
      if (delta < 0)
        zoomout_action_cb(canvas);
      else
        zoomin_action_cb(canvas);
    }
    else
    {
      float posy = IupGetFloat(canvas, "POSY");
      posy -= delta * IupGetFloat(canvas, "DY") / 10.0f;
      IupSetFloat(canvas, "POSY", posy);
      IupUpdate(canvas);
    }
    return IUP_DEFAULT;
  }
  
  int canvas_button_cb(Ihandle* canvas, int button, int pressed, int x, int y)
  {
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (image)
    {
      int cursor_x = x, cursor_y = y;
      int view_x, view_y, view_width, view_height;
      double zoom_factor = view_zoom_rect(canvas, image->width, image->height, &view_x, &view_y, &view_width, &view_height);
  
      /* y is top-down in IUP */
      int canvas_height = IupGetInt2(canvas, "DRAWSIZE");
      y = canvas_height - y - 1;
  
      /* inside image area */
      if (x > view_x && y > view_y && x < view_x + view_width && y < view_y + view_height)
      {
        view_zoom_offset(view_x, view_y, image->width, image->height, zoom_factor, &x, &y);
        
        if (button == IUP_BUTTON1)
        {
          if (pressed)
          {
            IupSetInt(canvas, "START_X", x);
            IupSetInt(canvas, "START_Y", y);
            IupSetInt(canvas, "START_CURSOR_X", cursor_x);
            IupSetInt(canvas, "START_CURSOR_Y", cursor_y);
          }
          else
          {
            Ihandle* toolbox = (Ihandle*)IupGetAttribute(canvas, "TOOLBOX");
            int tool_index = IupGetInt(toolbox, "TOOLINDEX");
  
            if (tool_index == 1)  /* Color Picker */
            {
              Ihandle* color = IupGetDialogChild(toolbox, "COLOR");
              unsigned char** data = (unsigned char**)image->data;
              unsigned char r, g, b;
              int offset;
  
              offset = y * image->width + x;
              r = data[0][offset];
              g = data[1][offset];
              b = data[2][offset];
  
              IupSetRGB(color, "BGCOLOR", r, g, b);
              IupSetRGB(toolbox, "TOOLCOLOR", r, g, b);
            }
            else if (tool_index == 2)  /* Pencil */
            {
              int start_x = IupGetInt(canvas, "START_X");
              int start_y = IupGetInt(canvas, "START_Y");
              double res = IupGetDouble(NULL, "SCREENDPI") / 25.4;
              unsigned char** data = (unsigned char**)image->data;
              unsigned char r, g, b;
  
              int line_width = IupGetInt(toolbox, "TOOLWIDTH");
              IupGetRGB(toolbox, "TOOLCOLOR", &r, &g, &b);
  
              /* do not use line style here */
              cdCanvas* cd_canvas = cdCreateCanvasf(CD_IMAGERGB, "%dx%d %p %p %p -r%g", image->width, image->height, data[0], data[1], data[2], res);
              cdCanvasForeground(cd_canvas, cdEncodeColor(r, g, b));
              cdCanvasLineWidth(cd_canvas, line_width);
              cdCanvasLine(cd_canvas, start_x, start_y, x, y);
              cdKillCanvas(cd_canvas);
  
              IupSetAttribute(canvas, "DIRTY", "Yes");
  
              IupUpdate(canvas);
  
              IupSetInt(canvas, "START_X", x);
              IupSetInt(canvas, "START_Y", y);
            }
            else if (tool_index >= 3 && tool_index <= 8)  /* Shapes */
            {
              if (IupGetAttribute(canvas, "OVERLAY"))
              {
                int start_x = IupGetInt(canvas, "START_X");
                int start_y = IupGetInt(canvas, "START_Y");
                int line_width = IupGetInt(toolbox, "TOOLWIDTH");
                int line_style = IupGetInt(toolbox, "TOOLSTYLE") - 1;
                double res = IupGetDouble(NULL, "SCREENDPI") / 25.4;
                unsigned char** data = (unsigned char**)image->data;
                unsigned char r, g, b;
  
                IupGetRGB(toolbox, "TOOLCOLOR", &r, &g, &b);
  
                cdCanvas* cd_canvas = cdCreateCanvasf(CD_IMAGERGB, "%dx%d %p %p %p -r%g", image->width, image->height, data[0], data[1], data[2], res);
                cdCanvasForeground(cd_canvas, cdEncodeColor(r, g, b));
                cdCanvasLineWidth(cd_canvas, line_width);
                if (line_width == 1)
                  cdCanvasLineStyle(cd_canvas, line_style);
  
                if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "LINE") == 0)
                  cdCanvasLine(cd_canvas, start_x, start_y, x, y);
                else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "RECT") == 0)
                    cdCanvasRect(cd_canvas, start_x, x, start_y, y);
                else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "BOX") == 0)
                  cdCanvasBox(cd_canvas, start_x, x, start_y, y);
                else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "ELLIPSE") == 0)
                  cdCanvasArc(cd_canvas, (x + start_x) / 2, (y + start_y) / 2, abs(x - start_x), abs(y - start_y), 0, 360);
                else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "OVAL") == 0)
                  cdCanvasSector(cd_canvas, (x + start_x) / 2, (y + start_y) / 2, abs(x - start_x), abs(y - start_y), 0, 360);
                else if (strcmp(IupGetAttribute(canvas, "OVERLAY"), "TEXT") == 0)
                {
                  cdCanvasTextAlignment(cd_canvas, CD_SOUTH_WEST);
                  cdCanvasNativeFont(cd_canvas, IupGetAttribute(toolbox, "TOOLFONT"));
                  cdCanvasText(cd_canvas, x, y, IupGetAttribute(toolbox, "TOOLTEXT"));
                }
  
                cdKillCanvas(cd_canvas);
  
                IupSetAttribute(canvas, "OVERLAY", NULL);
                IupSetAttribute(canvas, "DIRTY", "Yes");
  
                IupUpdate(canvas);
              }
            }
            else if (tool_index == 9)  /* Fill Color */
            {
              double tol_percent = IupGetDouble(toolbox, "TOOLFILLTOL");
              unsigned char r, g, b;
              IupGetRGB(toolbox, "TOOLCOLOR", &r, &g, &b);
  
              image_flood_fill(image, x, y, cdEncodeColor(r, g, b), tol_percent);
              IupSetAttribute(canvas, "DIRTY", "Yes");
  
              IupUpdate(canvas);
            }
          }
        }
        else if (button == IUP_BUTTON3)
        {
          if (!pressed)
          {
            Ihandle* toolbox = (Ihandle*)IupGetAttribute(canvas, "TOOLBOX");
            int tool_index = IupGetInt(toolbox, "TOOLINDEX");
            if (tool_index == 8)  /* Text */
              tool_get_text(toolbox);
          }
        }
      }
    }
  
    return IUP_DEFAULT;
  }
  
  int canvas_motion_cb(Ihandle* canvas, int x, int y, char *status)
  {
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (image)
    {
      int cursor_x = x, cursor_y = y;
      int view_x, view_y, view_width, view_height;
      double zoom_factor = view_zoom_rect(canvas, image->width, image->height, &view_x, &view_y, &view_width, &view_height);
  
      /* y is top-down in IUP */
      int canvas_height = IupGetInt2(canvas, "DRAWSIZE");
      y = canvas_height - y - 1;
  
      /* inside image area */
      if (x > view_x && y > view_y && x < view_x + view_width && y < view_y + view_height)
      {
        Ihandle* status_lbl = IupGetDialogChild(canvas, "STATUSLABEL");
        unsigned char** data = (unsigned char**)image->data;
        unsigned char r, g, b;
        int offset;
  
        view_zoom_offset(view_x, view_y, image->width, image->height, zoom_factor, &x, &y);
  
        offset = y * image->width + x; 
        r = data[0][offset];
        g = data[1][offset];
        b = data[2][offset];
  
        IupSetStrf(status_lbl, "TITLE", "(%4d, %4d) = %3d %3d %3d", x, y, (int)r, (int)g, (int)b);
  
        if (iup_isbutton1(status)) /* button1 is pressed */
        {
          Ihandle* toolbox = (Ihandle*)IupGetAttribute(canvas, "TOOLBOX");
          int tool_index = IupGetInt(toolbox, "TOOLINDEX");
  
          if (tool_index == 0)  /* Pointer */
          {
            int start_cursor_x = IupGetInt(canvas, "START_CURSOR_X");
            int start_cursor_y = IupGetInt(canvas, "START_CURSOR_Y");
  
            int canvas_width = IupGetInt(canvas, "DRAWSIZE");
  
            scroll_move(canvas, canvas_width, canvas_height, cursor_x - start_cursor_x, cursor_y - start_cursor_y, view_width, view_height);
  
            IupSetInt(canvas, "START_CURSOR_X", cursor_x);
            IupSetInt(canvas, "START_CURSOR_Y", cursor_y);
          }
          else if (tool_index == 2)  /* Pencil */
          {
            int start_x = IupGetInt(canvas, "START_X");
            int start_y = IupGetInt(canvas, "START_Y");
            double res = IupGetDouble(NULL, "SCREENDPI") / 25.4;
  
            int line_width = IupGetInt(toolbox, "TOOLWIDTH");
            IupGetRGB(toolbox, "TOOLCOLOR", &r, &g, &b);
  
            /* do not use line style here */
            cdCanvas* cd_canvas = cdCreateCanvasf(CD_IMAGERGB, "%dx%d %p %p %p -r%g", image->width, image->height, data[0], data[1], data[2], res);
            cdCanvasForeground(cd_canvas, cdEncodeColor(r, g, b));
            cdCanvasLineWidth(cd_canvas, line_width);
            cdCanvasLine(cd_canvas, start_x, start_y, x, y);
            cdKillCanvas(cd_canvas);
  
            IupSetAttribute(canvas, "DIRTY", "Yes");
  
            IupUpdate(canvas);
  
            IupSetInt(canvas, "START_X", x);
            IupSetInt(canvas, "START_Y", y);
          }
          else if (tool_index >= 3 && tool_index <= 8)  /* Shapes */
          {
            const char* shapes[] = { "LINE", "RECT", "BOX", "ELLIPSE", "OVAL", "TEXT" };
            IupSetInt(canvas, "END_X", x);
            IupSetInt(canvas, "END_Y", y);
            IupSetAttribute(canvas, "OVERLAY", shapes[tool_index - 3]);
            IupUpdate(canvas);
          }
        }
      }
    }
  
    return IUP_DEFAULT;
  }
  
  int zoom_valuechanged_cb(Ihandle* val)
  {
    double zoom_index = IupGetDouble(val, "VALUE");
    zoom_update(val, zoom_index);
    return IUP_DEFAULT;
  }
  
  int dropfiles_cb(Ihandle* ih, const char* filename)
  {
    if (save_check(ih))
      open_file(ih, filename);
  
    return IUP_DEFAULT;
  }
  
  int file_menu_open_cb(Ihandle* ih)
  {
    Ihandle* item_revert = IupGetDialogChild(ih, "ITEM_REVERT");
    Ihandle* item_save = IupGetDialogChild(ih, "ITEM_SAVE");
    Ihandle* canvas = IupGetDialogChild(ih, "CANVAS");
    char* filename = IupGetAttribute(canvas, "FILENAME");
    int dirty = IupGetInt(canvas, "DIRTY");
  
    if (dirty)
      IupSetAttribute(item_save, "ACTIVE", "YES");
    else
      IupSetAttribute(item_save, "ACTIVE", "NO");
  
    if (dirty && filename)
      IupSetAttribute(item_revert, "ACTIVE", "YES");
    else
      IupSetAttribute(item_revert, "ACTIVE", "NO");
    return IUP_DEFAULT;
  }
  
  int edit_menu_open_cb(Ihandle* ih)
  {
    Ihandle *clipboard = IupClipboard(); 
  
    Ihandle *item_paste = IupGetDialogChild(ih, "ITEM_PASTE");
  
    if (!IupGetInt(clipboard, "IMAGEAVAILABLE"))
      IupSetAttribute(item_paste, "ACTIVE", "NO");
    else
      IupSetAttribute(item_paste, "ACTIVE", "YES");
  
    IupDestroy(clipboard);
    return IUP_DEFAULT;
  }
  
  int config_recent_cb(Ihandle* ih)
  {
    if (save_check(ih))
    {
      char* filename = IupGetAttribute(ih, "RECENTFILENAME");
      open_file(ih, filename);
    }
    return IUP_DEFAULT;
  }
  
  int item_new_action_cb(Ihandle* item_new)
  {
    if (save_check(item_new))
    {
      Ihandle* canvas = IupGetDialogChild(item_new, "CANVAS");
      Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
      int width = IupConfigGetVariableIntDef(config, "NewImage", "Width", 640);
      int height = IupConfigGetVariableIntDef(config, "NewImage", "Height", 480);
  
      if (IupGetParam("New Image", NULL, NULL, "Width: %i[1,]\nHeight: %i[1,]\n", &width, &height, NULL))
      {
        imImage* image = imImageCreate(width, height, IM_RGB, IM_BYTE);
        image_fill_white(image);
  
        IupConfigSetVariableInt(config, "NewImage", "Width", width);
        IupConfigSetVariableInt(config, "NewImage", "Height", height);
  
        set_new_image(canvas, image, NULL, 0);
      }
    }
  
    return IUP_DEFAULT;
  }
  
  int item_open_action_cb(Ihandle* item_open)
  {
    if (!save_check(item_open))
      return IUP_DEFAULT;
  
    return select_file(IupGetDialog(item_open), 1);
  }
  
  int item_saveas_action_cb(Ihandle* item_saveas)
  {
    return select_file(IupGetDialog(item_saveas), 0);
  }
  
  int item_save_action_cb(Ihandle* item_save)
  {
    Ihandle* canvas = IupGetDialogChild(item_save, "CANVAS");
    char* filename = IupGetAttribute(canvas, "FILENAME");
    if (!filename)
      item_saveas_action_cb(item_save);
    else   
    {
      /* test again because in can be called using the hot key */
      int dirty = IupGetInt(canvas, "DIRTY");
      if (dirty)
        save_file(canvas);
    }
    return IUP_DEFAULT;
  }
  
  int item_revert_action_cb(Ihandle* item_revert)
  {
    Ihandle* canvas = IupGetDialogChild(item_revert, "CANVAS");
    char* filename = IupGetAttribute(canvas, "FILENAME");
    open_file(item_revert, filename);
    return IUP_DEFAULT;
  }
  
  int item_pagesetup_action_cb(Ihandle* item_pagesetup)
  {
    Ihandle* canvas = IupGetDialogChild(item_pagesetup, "CANVAS");
    Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
    int margin_width = IupConfigGetVariableIntDef(config, "Print", "MarginWidth", 20);
    int margin_height = IupConfigGetVariableIntDef(config, "Print", "MarginHeight", 20);
  
    if (IupGetParam("Page Setup", NULL, NULL, "Margin Width (mm): %i[1,]\nMargin Height (mm): %i[1,]\n", &margin_width, &margin_height, NULL))
    {
      IupConfigSetVariableInt(config, "Print", "MarginWidth", margin_width);
      IupConfigSetVariableInt(config, "Print", "MarginHeight", margin_height);
    }
  
    return IUP_DEFAULT;
  }
  
  int item_print_action_cb(Ihandle* item_print)
  {
    Ihandle* canvas = IupGetDialogChild(item_print, "CANVAS");
    imImage* image;
    char* title = IupGetAttribute(IupGetDialog(item_print), "TITLE");
  
    cdCanvas* cd_canvas = cdCreateCanvasf(CD_PRINTER, "%s -d", title);
    if (!cd_canvas)
      return IUP_DEFAULT;
  
    /* do NOT draw the background, use the paper color */
  
    /* draw the image at the center of the canvas */
    image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    if (image)
    {
      int x, y, canvas_width, canvas_height, view_width, view_height;
      double canvas_width_mm, canvas_height_mm;
      Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
      int margin_width = IupConfigGetVariableIntDef(config, "Print", "MarginWidth", 20);
      int margin_height = IupConfigGetVariableIntDef(config, "Print", "MarginHeight", 20);
  
      cdCanvasGetSize(cd_canvas, &canvas_width, &canvas_height, &canvas_width_mm, &canvas_height_mm);
  
      /* convert to pixels */
      margin_width = (int)((margin_width * canvas_width) / canvas_width_mm);
      margin_height = (int)((margin_height * canvas_height) / canvas_height_mm);
  
      view_fit_rect(canvas_width - 2 * margin_width, canvas_height - 2 * margin_height, 
                    image->width, image->height, 
                    &view_width, &view_height);
  
      x = (canvas_width - view_width) / 2;
      y = (canvas_height - view_height) / 2;
  
      imcdCanvasPutImage(cd_canvas, image, x, y, view_width, view_height, 0, 0, 0, 0);
    }
  
    cdKillCanvas(cd_canvas);
    return IUP_DEFAULT;
  }
  
  int item_exit_action_cb(Ihandle* item_exit)
  {
    Ihandle* dlg = IupGetDialog(item_exit);
    Ihandle* config = (Ihandle*)IupGetAttribute(dlg, "CONFIG");
    Ihandle* canvas = IupGetDialogChild(dlg, "CANVAS");
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    Ihandle* toolbox = (Ihandle*)IupGetAttribute(dlg, "TOOLBOX");
  
    if (!save_check(item_exit))
      return IUP_IGNORE;  /* to abort the CLOSE_CB callback */
  
    if (IupGetInt(toolbox, "VISIBLE"))
    {
      IupConfigDialogClosed(config, toolbox, "Toolbox");
      IupHide(toolbox);
    }
  
    if (image)
      imImageDestroy(image);
  
    IupConfigDialogClosed(config, dlg, "MainWindow");
    IupConfigSave(config);
    IupDestroy(config);
    return IUP_CLOSE;
  }
  
  int item_copy_action_cb(Ihandle* item_copy) 
  {
    Ihandle* canvas = IupGetDialogChild(item_copy, "CANVAS");
    imImage* image = (imImage*)IupGetAttribute(canvas, "IMAGE");
    Ihandle *clipboard = IupClipboard();
    IupSetAttribute(clipboard, "NATIVEIMAGE", (char*)IupGetImageNativeHandle(image));
    IupDestroy(clipboard);
    return IUP_DEFAULT;
  }
  
  int item_paste_action_cb(Ihandle* item_paste) 
  {
    if (save_check(item_paste))
    {
      Ihandle* canvas = IupGetDialogChild(item_paste, "CANVAS");
  
      Ihandle *clipboard = IupClipboard();
      imImage* image = IupGetNativeHandleImage(IupGetAttribute(clipboard, "NATIVEIMAGE"));
      IupDestroy(clipboard);
  
      if (!image)
      {
        show_error("Invalid Clipboard Data", 1);
        return IUP_DEFAULT;
      }
  
      set_new_image(canvas, image, NULL, 1);  /* set dirty */
    }
    return IUP_DEFAULT;
  }
  
  int item_background_action_cb(Ihandle* item_background)
  {
    Ihandle* canvas = IupGetDialogChild(item_background, "CANVAS");
    Ihandle* config = (Ihandle*)IupGetAttribute(canvas, "CONFIG");
    Ihandle* colordlg = IupColorDlg();
    const char* background = IupConfigGetVariableStrDef(config, "Canvas", "Background", "255 255 255");
    IupSetStrAttribute(colordlg, "VALUE", background);
    IupSetAttributeHandle(colordlg, "PARENTDIALOG", IupGetDialog(item_background));
  
    IupPopup(colordlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
  
    if (IupGetInt(colordlg, "STATUS") == 1)
    {
      background = IupGetAttribute(colordlg, "VALUE");
      IupConfigSetVariableStr(config, "Canvas", "Background", background);
  
      IupUpdate(canvas);
    }
  
    IupDestroy(colordlg);
    return IUP_DEFAULT;
  }
  
  int item_zoomgrid_action_cb(Ihandle* ih)
  {
    Ihandle* item_zoomgrid = IupGetDialogChild(ih, "ZOOMGRID");
    Ihandle* canvas = IupGetDialogChild(ih, "CANVAS");
    Ihandle* config = (Ihandle*)IupGetAttribute(ih, "CONFIG");
  
    if (IupGetInt(item_zoomgrid, "VALUE"))
      IupSetAttribute(item_zoomgrid, "VALUE", "OFF");
    else
      IupSetAttribute(item_zoomgrid, "VALUE", "ON");
  
    IupConfigSetVariableStr(config, "Canvas", "ZoomGrid", IupGetAttribute(item_zoomgrid, "VALUE"));
  
    IupUpdate(canvas);
    return IUP_DEFAULT;
  }
  
  int item_toolbar_action_cb(Ihandle* item_toolbar)
  {
    Ihandle* toolbar = IupGetDialogChild(item_toolbar, "TOOLBAR");
    Ihandle* config = (Ihandle*)IupGetAttribute(item_toolbar, "CONFIG");
  
    toggle_bar_visibility(item_toolbar, toolbar);
  
    IupConfigSetVariableStr(config, "MainWindow", "Toolbar", IupGetAttribute(item_toolbar, "VALUE"));
    return IUP_DEFAULT;
  }
  
  int item_toolbox_action_cb(Ihandle* item_toolbox)
  {
    Ihandle* toolbox = (Ihandle*)IupGetAttribute(item_toolbox, "TOOLBOX");
    Ihandle* config = (Ihandle*)IupGetAttribute(item_toolbox, "CONFIG");
  
    if (IupGetInt(toolbox, "VISIBLE"))
    {
      IupSetAttribute(item_toolbox, "VALUE", "OFF");
      IupConfigDialogClosed(config, toolbox, "Toolbox");
      IupHide(toolbox);
    }
    else
    {
      IupSetAttribute(item_toolbox, "VALUE", "ON");
      IupConfigDialogShow(config, toolbox, "Toolbox");
    }
  
    IupConfigSetVariableStr(config, "MainWindow", "Toolbox", IupGetAttribute(item_toolbox, "VALUE"));
    return IUP_DEFAULT;
  }
  
  int item_statusbar_action_cb(Ihandle* item_statusbar)
  {
    Ihandle* statusbar = IupGetDialogChild(item_statusbar, "STATUSBAR");
    Ihandle* config = (Ihandle*)IupGetAttribute(item_statusbar, "CONFIG");
  
    toggle_bar_visibility(item_statusbar, statusbar);
  
    IupConfigSetVariableStr(config, "MainWindow", "Statusbar", IupGetAttribute(item_statusbar, "VALUE"));
    return IUP_DEFAULT;
  }
  
  int item_help_action_cb(void)
  {
    IupHelp("http://www.tecgraf.puc-rio.br/iup");
    return IUP_DEFAULT;
  }
  
  int item_about_action_cb(void)
  {
    IupMessage("About", "   Simple Paint\n\nAuthors:\n   Gustavo Lyrio\n   Antonio Scuri");
    return IUP_DEFAULT;
  }
  
  int toolbox_close_cb(Ihandle* toolbox)
  {
    Ihandle* config = (Ihandle*)IupGetAttribute(toolbox, "CONFIG");
    Ihandle* item_toolbox = (Ihandle*)IupGetAttribute(toolbox, "TOOLBOXMENU");
  
    IupConfigDialogClosed(config, toolbox, "Toolbox");
  
    IupSetAttribute(item_toolbox, "VALUE", "OFF");
    IupConfigSetVariableStr(config, "MainWindow", "Toolbox", "OFF");
    return IUP_DEFAULT;
  }
  
  int tool_action_cb(Ihandle* ih, int state)
  {
    if (state == 1)
    {
      Ihandle* canvas = (Ihandle*)IupGetAttribute(ih, "CANVAS");
      int tool_index = IupGetInt(ih, "TOOLINDEX");
      IupSetInt(IupGetDialog(ih), "TOOLINDEX", tool_index);
  
      if (tool_index == 0)
        IupSetAttribute(canvas, "CURSOR", "ARROW");
      else
        IupSetAttribute(canvas, "CURSOR", "CROSS");
  
      if (tool_index == 8)
        tool_get_text(IupGetDialog(ih));
    }
    return IUP_DEFAULT;
  }
  
  int toolcolor_action_cb(Ihandle* ih)
  {
    Ihandle* colordlg = IupColorDlg();
    const char* color = IupGetAttribute(ih, "BGCOLOR");
    IupSetStrAttribute(colordlg, "VALUE", color);
    IupSetAttributeHandle(colordlg, "PARENTDIALOG", IupGetDialog(ih));
  
    IupPopup(colordlg, IUP_CENTER, IUP_CENTER);
  
    if (IupGetInt(colordlg, "STATUS") == 1)
    {
      color = IupGetAttribute(colordlg, "VALUE");
  
      IupSetStrAttribute(ih, "BGCOLOR", color);           
      IupSetStrAttribute(IupGetDialog(ih), "TOOLCOLOR", color);
    }
  
    IupDestroy(colordlg);
    return IUP_DEFAULT;
  }
  
  int toolwidth_valuechanged_cb(Ihandle* ih)
  {
    char* value = IupGetAttribute(ih, "VALUE");
    IupSetStrAttribute(IupGetDialog(ih), "TOOLWIDTH", value);
    return IUP_DEFAULT;
  }
  
  int toolstyle_valuechanged_cb(Ihandle* ih)
  {
    char* value = IupGetAttribute(ih, "VALUE");
    IupSetStrAttribute(IupGetDialog(ih), "TOOLSTYLE", value);
    return IUP_DEFAULT;
  }
  
  int toolfont_action_cb(Ihandle* ih)
  {
    Ihandle* font_dlg = IupFontDlg();
    char* font = IupGetAttribute(ih, "TOOLFONT");
    IupSetAttributeHandle(font_dlg, "PARENTDIALOG", IupGetDialog(ih));
    IupSetStrAttribute(font_dlg, "VALUE", font);
  
    IupPopup(font_dlg, IUP_CENTER, IUP_CENTER);
  
    if (IupGetInt(font_dlg, "STATUS") == 1)
    {
      font = IupGetAttribute(font_dlg, "VALUE");
      IupSetStrAttribute(IupGetDialog(ih), "TOOLFONT", font);
    }
    IupDestroy(font_dlg);
    return IUP_DEFAULT;
  }
  
  int toolfilltol_valuechanged_cb(Ihandle* ih)
  {
    Ihandle* filltol_label = IupGetDialogChild(ih, "FILLTOLLABEL");
    double value = IupGetDouble(ih, "VALUE");
    IupSetStrf(filltol_label, "TITLE", "Tol.: %.0f%%", value);
    IupSetDouble(IupGetDialog(ih), "TOOLFILLTOL", value);
    return IUP_DEFAULT;
  }
  
  int main_dlg_move_cb(Ihandle* dlg, int x, int y)
  {
    Ihandle* toolbox = (Ihandle*)IupGetAttribute(dlg, "TOOLBOX");
  
    int old_x = IupGetInt(dlg, "_OLD_X");
    int old_y = IupGetInt(dlg, "_OLD_Y");
  
    if (old_x == x && old_y == y)
      return IUP_DEFAULT;
    
    if (IupGetInt(toolbox, "VISIBLE"))
    {
      int tb_x = IupGetInt(toolbox, "X");
      int tb_y = IupGetInt(toolbox, "Y");
  
      tb_x += x - old_x;
      tb_y += y - old_y;
  
      IupShowXY(toolbox, tb_x, tb_y);
    }
  
    IupSetInt(dlg, "_OLD_X", x);
    IupSetInt(dlg, "_OLD_Y", y);
  
    return IUP_DEFAULT;
  }
  
  
  
  /********************************** Main *****************************************/
  
  
  Ihandle* create_main_menu(Ihandle *config)
  {
    Ihandle *menu, *sub_menu_file;
    Ihandle *file_menu, *item_exit, *item_new, *item_open, *item_save, *item_saveas, *item_revert;
    Ihandle *sub_menu_edit, *edit_menu, *item_copy, *item_paste, *item_print, *item_pagesetup;
    Ihandle *sub_menu_help, *help_menu, *item_help, *item_about;
    Ihandle *sub_menu_view, *view_menu, *item_toolbar, *item_statusbar;
    Ihandle *item_zoomin, *item_zoomout, *item_actualsize;
    Ihandle *recent_menu, *item_background, *item_toolbox, *item_zoomgrid;
  
    item_new = IupItem("&New\tCtrl+N", NULL);
    IupSetAttribute(item_new, "IMAGE", "IUP_FileNew");
    IupSetCallback(item_new, "ACTION", (Icallback)item_new_action_cb);
  
    item_open = IupItem("&Open...\tCtrl+O", NULL);
    IupSetAttribute(item_open, "IMAGE", "IUP_FileOpen");
    IupSetCallback(item_open, "ACTION", (Icallback)item_open_action_cb);
  
    item_save = IupItem("&Save\tCtrl+S", NULL);
    IupSetAttribute(item_save, "NAME", "ITEM_SAVE");
    IupSetAttribute(item_save, "IMAGE", "IUP_FileSave");
    IupSetCallback(item_save, "ACTION", (Icallback)item_save_action_cb);
  
    item_saveas = IupItem("Save &As...", NULL);
    IupSetAttribute(item_saveas, "NAME", "ITEM_SAVEAS");
    IupSetCallback(item_saveas, "ACTION", (Icallback)item_saveas_action_cb);
  
    item_revert = IupItem("&Revert", NULL);
    IupSetAttribute(item_revert, "NAME", "ITEM_REVERT");
    IupSetCallback(item_revert, "ACTION", (Icallback)item_revert_action_cb);
  
    item_pagesetup = IupItem("Page Set&up...", NULL);
    IupSetCallback(item_pagesetup, "ACTION", (Icallback)item_pagesetup_action_cb);
  
    item_print = IupItem("&Print...\tCtrl+P", NULL);
    IupSetCallback(item_print, "ACTION", (Icallback)item_print_action_cb);
  
    item_exit = IupItem("E&xit", NULL);
    IupSetCallback(item_exit, "ACTION", (Icallback)item_exit_action_cb);
  
    item_copy = IupItem("&Copy\tCtrl+C", NULL);
    IupSetAttribute(item_copy, "NAME", "ITEM_COPY");
    IupSetAttribute(item_copy, "IMAGE", "IUP_EditCopy");
    IupSetCallback(item_copy, "ACTION", (Icallback)item_copy_action_cb);
  
    item_paste = IupItem("&Paste\tCtrl+V", NULL);
    IupSetAttribute(item_paste, "NAME", "ITEM_PASTE");
    IupSetAttribute(item_paste, "IMAGE", "IUP_EditPaste");
    IupSetCallback(item_paste, "ACTION", (Icallback)item_paste_action_cb);
  
    item_zoomin = IupItem("Zoom &In\tCtrl++", NULL);
    IupSetAttribute(item_zoomin, "IMAGE", "IUP_ZoomIn");
    IupSetCallback(item_zoomin, "ACTION", (Icallback)zoomin_action_cb);
  
    item_zoomout = IupItem("Zoom &Out\tCtrl+-", NULL);
    IupSetAttribute(item_zoomout, "IMAGE", "IUP_ZoomOut");
    IupSetCallback(item_zoomout, "ACTION", (Icallback)zoomout_action_cb);
  
    item_actualsize = IupItem("&Actual Size\tCtrl+0", NULL);
    IupSetAttribute(item_actualsize, "IMAGE", "IUP_ZoomActualSize");
    IupSetCallback(item_actualsize, "ACTION", (Icallback)actualsize_action_cb);
  
    item_zoomgrid = IupItem("&Zoom Grid", NULL);
    IupSetCallback(item_zoomgrid, "ACTION", (Icallback)item_zoomgrid_action_cb);
    IupSetAttribute(item_zoomgrid, "VALUE", "ON");
    IupSetAttribute(item_zoomgrid, "NAME", "ZOOMGRID");
  
    item_background = IupItem("&Background...", NULL);
    IupSetCallback(item_background, "ACTION", (Icallback)item_background_action_cb);
  
    item_toolbar = IupItem("&Toobar", NULL);
    IupSetCallback(item_toolbar, "ACTION", (Icallback)item_toolbar_action_cb);
    IupSetAttribute(item_toolbar, "VALUE", "ON");
  
    item_toolbox = IupItem("&Toobox", NULL);
    IupSetCallback(item_toolbox, "ACTION", (Icallback)item_toolbox_action_cb);
    IupSetAttribute(item_toolbox, "NAME", "TOOLBOXMENU");
  
    item_statusbar = IupItem("&Statusbar", NULL);
    IupSetCallback(item_statusbar, "ACTION", (Icallback)item_statusbar_action_cb);
    IupSetAttribute(item_statusbar, "VALUE", "ON");
  
    item_help = IupItem("&Help...", NULL);
    IupSetCallback(item_help, "ACTION", (Icallback)item_help_action_cb);
  
    item_about = IupItem("&About...", NULL);
    IupSetCallback(item_about, "ACTION", (Icallback)item_about_action_cb);
  
    recent_menu = IupMenu(NULL);
  
    file_menu = IupMenu(
      item_new,
      item_open,
      item_save,
      item_saveas,
      item_revert,
      IupSeparator(),
      item_pagesetup,
      item_print,
      IupSeparator(),
      IupSubmenu("Recent &Files", recent_menu),
      IupSeparator(),
      item_exit,
      NULL);
    edit_menu = IupMenu(
      item_copy,
      item_paste,
      NULL);
    view_menu = IupMenu(
      item_zoomin,
      item_zoomout,
      item_actualsize,
      item_zoomgrid,
      IupSeparator(),
      item_background,
      IupSeparator(),
      item_toolbar,
      item_toolbox,
      item_statusbar,
      NULL);
    help_menu = IupMenu(
      item_help,
      item_about,
      NULL);
  
    IupSetCallback(file_menu, "OPEN_CB", (Icallback)file_menu_open_cb);
    IupSetCallback(edit_menu, "OPEN_CB", (Icallback)edit_menu_open_cb);
  
    sub_menu_file = IupSubmenu("&File", file_menu);
    sub_menu_edit = IupSubmenu("&Edit", edit_menu);
    sub_menu_view = IupSubmenu("&View", view_menu);
    sub_menu_help = IupSubmenu("&Help", help_menu);
  
    menu = IupMenu(
      sub_menu_file,
      sub_menu_edit,
      sub_menu_view,
      sub_menu_help,
      NULL);
  
    /* Initialize variables from the configuration file */
  
    IupConfigRecentInit(config, recent_menu, config_recent_cb, 10);
  
    if (!IupConfigGetVariableIntDef(config, "Canvas", "ZoomGrid", 1))
      IupSetAttribute(item_zoomgrid, "VALUE", "OFF");
  
    if (!IupConfigGetVariableIntDef(config, "MainWindow", "Toolbar", 1))
      IupSetAttribute(item_toolbar, "VALUE", "OFF");
  
    if (!IupConfigGetVariableIntDef(config, "MainWindow", "Statusbar", 1))
      IupSetAttribute(item_statusbar, "VALUE", "OFF");
  
    return menu;
  }
  
  Ihandle* create_toolbar(Ihandle *config)
  {
    Ihandle *toolbar;
    Ihandle *btn_copy, *btn_paste, *btn_new, *btn_open, *btn_save, *btn_zoomgrid;
  
    IupSetHandle("PaintZoomGrid", load_image_PaintZoomGrid());
  
    btn_new = IupButton(NULL, NULL);
    IupSetAttribute(btn_new, "IMAGE", "IUP_FileNew");
    IupSetAttribute(btn_new, "FLAT", "Yes");
    IupSetCallback(btn_new, "ACTION", (Icallback)item_new_action_cb);
    IupSetAttribute(btn_new, "TIP", "New (Ctrl+N)");
    IupSetAttribute(btn_new, "CANFOCUS", "No");
  
    btn_open = IupButton(NULL, NULL);
    IupSetAttribute(btn_open, "IMAGE", "IUP_FileOpen");
    IupSetAttribute(btn_open, "FLAT", "Yes");
    IupSetCallback(btn_open, "ACTION", (Icallback)item_open_action_cb);
    IupSetAttribute(btn_open, "TIP", "Open (Ctrl+O)");
    IupSetAttribute(btn_open, "CANFOCUS", "No");
  
    btn_save = IupButton(NULL, NULL);
    IupSetAttribute(btn_save, "IMAGE", "IUP_FileSave");
    IupSetAttribute(btn_save, "FLAT", "Yes");
    IupSetCallback(btn_save, "ACTION", (Icallback)item_save_action_cb);
    IupSetAttribute(btn_save, "TIP", "Save (Ctrl+S)");
    IupSetAttribute(btn_save, "CANFOCUS", "No");
  
    btn_copy = IupButton(NULL, NULL);
    IupSetAttribute(btn_copy, "IMAGE", "IUP_EditCopy");
    IupSetAttribute(btn_copy, "FLAT", "Yes");
    IupSetCallback(btn_copy, "ACTION", (Icallback)item_copy_action_cb);
    IupSetAttribute(btn_copy, "TIP", "Copy (Ctrl+C)");
    IupSetAttribute(btn_copy, "CANFOCUS", "No");
  
    btn_paste = IupButton(NULL, NULL);
    IupSetAttribute(btn_paste, "IMAGE", "IUP_EditPaste");
    IupSetAttribute(btn_paste, "FLAT", "Yes");
    IupSetCallback(btn_paste, "ACTION", (Icallback)item_paste_action_cb);
    IupSetAttribute(btn_paste, "TIP", "Paste (Ctrl+V)");
    IupSetAttribute(btn_paste, "CANFOCUS", "No");
  
    btn_zoomgrid = IupButton(NULL, NULL);
    IupSetAttribute(btn_zoomgrid, "IMAGE", "PaintZoomGrid");
    IupSetAttribute(btn_zoomgrid, "FLAT", "Yes");
    IupSetCallback(btn_zoomgrid, "ACTION", (Icallback)item_zoomgrid_action_cb);
    IupSetAttribute(btn_zoomgrid, "TIP", "Zoom Grid");
    IupSetAttribute(btn_paste, "CANFOCUS", "No");
  
    toolbar = IupHbox(
      btn_new,
      btn_open,
      btn_save,
      IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
      btn_copy,
      btn_paste,
      IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
      btn_zoomgrid,
      NULL);
    IupSetAttribute(toolbar, "MARGIN", "5x5");
    IupSetAttribute(toolbar, "GAP", "2");
    IupSetAttribute(toolbar, "NAME", "TOOLBAR");
  
    /* Initialize variables from the configuration file */
  
    if (!IupConfigGetVariableIntDef(config, "MainWindow", "Toolbar", 1))
    {
      IupSetAttribute(toolbar, "FLOATING", "YES");
      IupSetAttribute(toolbar, "VISIBLE", "NO");
    }
  
    return toolbar;
  }
  
  void create_toolbox(Ihandle* parent_dlg, Ihandle *config)
  {
    Ihandle *toolbox, *gbox, *vbox;
    Ihandle* item_toolbox = IupGetDialogChild(parent_dlg, "TOOLBOXMENU");
    Ihandle* canvas = IupGetDialogChild(parent_dlg, "CANVAS");
  
    IupSetHandle("PaintPointer", load_image_Pointer());
    IupSetHandle("PaintColorPicker", load_image_PaintColorPicker());
    IupSetHandle("PaintPencil", load_image_PaintPencil());
    IupSetHandle("PaintLine", load_image_PaintLine());
    IupSetHandle("PaintEllipse", load_image_PaintEllipse());
    IupSetHandle("PaintRect", load_image_PaintRect());
    IupSetHandle("PaintOval", load_image_PaintOval());
    IupSetHandle("PaintBox", load_image_PaintBox());
    IupSetHandle("PaintFill", load_image_PaintFill());
    IupSetHandle("PaintText", load_image_PaintText());
  
    gbox = IupGridBox(
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=0, IMAGE=PaintPointer, VALUE=ON, FLAT=Yes, TIP=\"Pointer\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=1, IMAGE=PaintColorPicker, FLAT=Yes, TIP=\"Color Picker\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=2, IMAGE=PaintPencil, FLAT=Yes, TIP=\"Pencil\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=3, IMAGE=PaintLine, FLAT=Yes, TIP=\"Line\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=4, IMAGE=PaintRect, FLAT=Yes, TIP=\"Hollow Rectangle\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=5, IMAGE=PaintBox, FLAT=Yes, TIP=\"Box (Filled Rectangle)\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=6, IMAGE=PaintEllipse, FLAT=Yes, TIP=\"Hollow Ellipse\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=7, IMAGE=PaintOval, FLAT=Yes, TIP=\"Oval (Filled Ellipse)\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=8, IMAGE=PaintText, FLAT=Yes, TIP=\"Text\""), "ACTION", (Icallback)tool_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupToggle(NULL, NULL), "TOOLINDEX=9, IMAGE=PaintFill, FLAT=Yes, TIP=\"Fill Color\""), "ACTION", (Icallback)tool_action_cb, NULL),
      NULL);
    IupSetAttribute(gbox, "GAPCOL", "2");
    IupSetAttribute(gbox, "GAPLIN", "2");
    IupSetAttribute(gbox, "MARGIN", "5x10");
    IupSetAttribute(gbox, "NUMDIV", "2");
  
    vbox = IupVbox(
      IupRadio(gbox),
      IupFrame(IupSetAttributes(IupVbox(
        IupSetAttributes(IupLabel("Color:"), "EXPAND=HORIZONTAL"),
        IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "NAME=COLOR, BGCOLOR=\"0 0 0\", RASTERSIZE=28x21"), "ACTION", toolcolor_action_cb, NULL),
        IupSetAttributes(IupLabel("Width:"), "EXPAND=HORIZONTAL"),
        IupSetCallbacks(IupSetAttributes(IupText(NULL), "SPIN=Yes, SPINMIN=1, RASTERSIZE=48x"), "VALUECHANGED_CB", toolwidth_valuechanged_cb, NULL),
        IupSetAttributes(IupLabel("Style:"), "EXPAND=HORIZONTAL"),
        IupSetCallbacks(IupSetAttributes(IupList(NULL), "DROPDOWN=Yes, VALUE=1, 1=\"____\", 2=\"----\", 3=\"....\", 4=\"-.-.\", 5=\"-..-..\""), "VALUECHANGED_CB", toolstyle_valuechanged_cb, NULL),
        IupSetAttributes(IupLabel("Tol.: 50%"), "EXPAND=HORIZONTAL, NAME=FILLTOLLABEL"),
        IupSetCallbacks(IupSetAttributes(IupVal(NULL), "NAME=FILLTOL, RASTERSIZE=60x30, VALUE=50, MAX=100"), "VALUECHANGED_CB", toolfilltol_valuechanged_cb, NULL),
        IupSetAttributes(IupLabel("Font:"), "EXPAND=HORIZONTAL"),
        IupSetCallbacks(IupSetAttributes(IupButton("F", NULL), "NAME=FONT, RASTERSIZE=21x21, FONT=\"Times, Bold Italic 11\""), "ACTION", toolfont_action_cb, NULL),
        NULL), "MARGIN=3x2, GAP=2, ALIGNMENT=ACENTER")),
      NULL);
    IupSetAttribute(vbox, "NMARGIN", "2x2");
    IupSetAttribute(vbox, "ALIGNMENT", "ACENTER");
  
    toolbox = IupDialog(vbox);
    IupSetAttribute(toolbox, "DIALOGFRAME", "Yes");
    IupSetAttribute(toolbox, "TITLE", "Tools");
    IupSetAttribute(toolbox, "FONTSIZE", "8");
    IupSetAttribute(toolbox, "TOOLBOX", "Yes");
    IupSetCallback(toolbox, "CLOSE_CB", (Icallback)toolbox_close_cb);
    IupSetAttributeHandle(toolbox, "PARENTDIALOG", parent_dlg);
  
    IupSetAttribute(toolbox, "TOOLCOLOR", "0 0 0");
    IupSetAttribute(toolbox, "TOOLWIDTH", "1");
    IupSetAttribute(toolbox, "TOOLSTYLE", "1");
    IupSetAttribute(toolbox, "TOOLFILLTOL", "50");
    IupSetStrAttribute(toolbox, "TOOLFONT", IupGetAttribute(parent_dlg, "FONT"));
  
    IupSetAttribute(toolbox, "CONFIG", (char*)config);
    IupSetAttribute(toolbox, "TOOLBOXMENU", (char*)item_toolbox);
    IupSetAttribute(toolbox, "CANVAS", (char*)canvas);
  
    IupSetAttribute(parent_dlg, "TOOLBOX", (char*)toolbox);
  
    /* Initialize variables from the configuration file */
  
    if (IupConfigGetVariableIntDef(config, "MainWindow", "Toolbox", 1))
    {
      /* configure the very first time to be aligned with the main window */
      if (!IupConfigGetVariableStr(config, "Toolbox", "X"))
      {
        Ihandle* canvas = IupGetDialogChild(parent_dlg, "CANVAS");
        int x = IupGetInt(canvas, "X");
        int y = IupGetInt(canvas, "Y");
        IupConfigSetVariableInt(config, "Toolbox", "X", x);
        IupConfigSetVariableInt(config, "Toolbox", "Y", y);
      }
  
      IupSetAttribute(item_toolbox, "VALUE", "ON");
      IupConfigDialogShow(config, toolbox, "Toolbox");
    }
  }
  
  Ihandle* create_statusbar(Ihandle *config)
  {
    Ihandle *statusbar;
  
    statusbar = IupHbox(
      IupSetAttributes(IupLabel("(0, 0) = 0   0   0"), "EXPAND=HORIZONTAL, PADDING=10x5, NAME=STATUSLABEL"),
      IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
      IupSetAttributes(IupLabel("0 x 0"), "SIZE=70x, PADDING=10x5, NAME=SIZELABEL, ALIGNMENT=ACENTER"),
      IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
      IupSetAttributes(IupLabel("100%"), "SIZE=30x, PADDING=10x5, NAME=ZOOMLABEL, ALIGNMENT=ARIGHT"),
      IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomOut, FLAT=Yes, TIP=\"Zoom Out (Ctrl+-)\""), "ACTION", zoomout_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupVal(NULL), "VALUE=0, MIN=-6, MAX=6, RASTERSIZE=150x25, NAME=ZOOMVAL"), "VALUECHANGED_CB", zoom_valuechanged_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomIn, FLAT=Yes, TIP=\"Zoom In (Ctrl++)\""), "ACTION", zoomin_action_cb, NULL),
      IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomActualSize, FLAT=Yes, TIP=\"Actual Size (Ctrl+0)\""), "ACTION", actualsize_action_cb, NULL),
      NULL);
    IupSetAttribute(statusbar, "NAME", "STATUSBAR");
    IupSetAttribute(statusbar, "ALIGNMENT", "ACENTER");
  
    /* Initialize variables from the configuration file */
  
    if (!IupConfigGetVariableIntDef(config, "MainWindow", "Statusbar", 1))
    {
      IupSetAttribute(statusbar, "FLOATING", "YES");
      IupSetAttribute(statusbar, "VISIBLE", "NO");
    }
  
    return statusbar;
  }
  
  Ihandle* create_main_dialog(Ihandle *config)
  {
    Ihandle *dlg, *vbox, *canvas;
  
    canvas = IupCanvas(NULL);
    IupSetAttribute(canvas, "NAME", "CANVAS");
    IupSetAttribute(canvas, "SCROLLBAR", "Yes");
    IupSetAttribute(canvas, "DIRTY", "NO");  /* custom attribute */
    IupSetCallback(canvas, "ACTION", (Icallback)canvas_action_cb);
    IupSetCallback(canvas, "DROPFILES_CB", (Icallback)dropfiles_cb);
    IupSetCallback(canvas, "MAP_CB", (Icallback)canvas_map_cb);
    IupSetCallback(canvas, "UNMAP_CB", (Icallback)canvas_unmap_cb);
    IupSetCallback(canvas, "WHEEL_CB", (Icallback)canvas_wheel_cb);
    IupSetCallback(canvas, "RESIZE_CB", (Icallback)canvas_resize_cb);
    IupSetCallback(canvas, "MOTION_CB", (Icallback)canvas_motion_cb);
    IupSetCallback(canvas, "BUTTON_CB", (Icallback)canvas_button_cb);
  
    vbox = IupVbox(
      create_toolbar(config),
      canvas,
      create_statusbar(config),
      NULL);
  
    dlg = IupDialog(vbox);
    IupSetAttributeHandle(dlg, "MENU", create_main_menu(config));
    IupSetAttribute(dlg, "SIZE", "HALFxHALF");
    IupSetCallback(dlg, "CLOSE_CB", (Icallback)item_exit_action_cb);
    IupSetCallback(dlg, "DROPFILES_CB", (Icallback)dropfiles_cb);
    IupSetCallback(dlg, "MOVE_CB", (Icallback)main_dlg_move_cb);
  
    IupSetCallback(dlg, "K_cN", (Icallback)item_new_action_cb);
    IupSetCallback(dlg, "K_cO", (Icallback)item_open_action_cb);
    IupSetCallback(dlg, "K_cS", (Icallback)item_save_action_cb);
    IupSetCallback(dlg, "K_cV", (Icallback)item_paste_action_cb);
    IupSetCallback(dlg, "K_cC", (Icallback)item_copy_action_cb);
    IupSetCallback(dlg, "K_cP", (Icallback)item_print_action_cb);
    IupSetCallback(dlg, "K_cMinus", (Icallback)zoomout_action_cb);
    IupSetCallback(dlg, "K_cPlus", (Icallback)zoomin_action_cb);
    IupSetCallback(dlg, "K_cEqual", (Icallback)zoomin_action_cb);
    IupSetCallback(dlg, "K_c0", (Icallback)actualsize_action_cb);
  
    /* parent for pre-defined dialogs in closed functions (IupMessage and IupAlarm) */
    IupSetAttributeHandle(NULL, "PARENTDIALOG", dlg);
  
    IupSetAttribute(dlg, "CONFIG", (char*)config);
  
    return dlg;
  }
  
  int main(int argc, char **argv)
  {
    Ihandle *dlg, *config;
  
    IupOpen(&argc, &argv);
    IupImageLibOpen();
  
    config = IupConfig();
    IupSetAttribute(config, "APP_NAME", "simple_paint");
    IupConfigLoad(config);
  
    dlg = create_main_dialog(config);
  
    /* show the dialog at the last position, with the last size */
    IupConfigDialogShow(config, dlg, "MainWindow");
  
    /* create and show the toolbox */
    create_toolbox(dlg, config);
  
    /* open a file from the command line (allow file association in Windows) */
    if (argc > 1 && argv[1])
    {
      const char* filename = argv[1];
      open_file(dlg, filename);
    }
  
    /* initialize the current file, if not already loaded */
    check_new_file(dlg);
  
    IupMainLoop();
  
    IupClose();
    return EXIT_SUCCESS;
  }
  