/** \file
* \brief FlatTree Control
*
* See Copyright Notice in "iup.h"
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

#include "iup.h"
#include "iupcbs.h"

#include "iup_assert.h"
#include "iup_object.h"
#include "iup_attrib.h"
#include "iup_str.h"
#include "iup_drv.h"
#include "iup_drvfont.h"
#include "iup_drvinfo.h"
#include "iup_stdcontrols.h"
#include "iup_layout.h"
#include "iup_image.h"
#include "iup_array.h"
#include "iup_drvdraw.h"
#include "iup_draw.h"
#include "iup_register.h"
#include "iup_flatscrollbar.h"
#include "iup_childtree.h"

#define IFLATTREE_UP        0
#define IFLATTREE_DOWN      1

#define IFLATTREE_TOGGLE_MARGIN 2
#define IFLATTREE_TOGGLE_BORDER 1
#define IFLATTREE_TOGGLE_SPACE  2

#define EXTRAWIDTH_SPACE 5

enum { IFLATTREE_EXPANDED, IFLATTREE_COLLAPSED };  /* state */
enum { IFLATTREE_BRANCH, IFLATTREE_LEAF };  /* kind */
enum { IFLATTREE_MARK_SINGLE, IFLATTREE_MARK_MULTIPLE };  /* mark_mode */

typedef struct _iFlatTreeNode 
{
  /* attributes */
  char* title;
  char* image;
  char* image_expanded;
  char* fg_color;
  char* bg_color;
  char* tip;
  char* font;
  int selected;        /* bool */
  int kind;
  int state;
  int toggle_visible;  /* bool */
  int toggle_value;    /* bool */
  void* userdata;
  char* extratext;

  /* aux */
  int id, depth, expanded;
  int height,  /* image+title height, does not includes spacing */
      width,   /* image+title width, includes also indentation and toggle_size*/
      title_width;

  struct _iFlatTreeNode *parent;
  struct _iFlatTreeNode *first_child;
  struct _iFlatTreeNode *brother;
} iFlatTreeNode;

struct _IcontrolData
{
  iupCanvas canvas;  /* from IupCanvas (must reserve it) */

  iFlatTreeNode *root_node;  /* tree of nodes, root node always exists and it always invisible */
  Iarray *node_array;   /* array of nodes indexed by id, needs to be updated when nodes are added or removed */

  /* aux */
  int has_focus, focus_id;
  int last_selected_id;
  int dragover_id, dragged_id;  /* internal drag&drop */
  clock_t last_clock;

  /* attributes */
  int add_expanded;
  int indentation;   /* horizontal space between one depth and the next */
  int show_rename;
  int icon_spacing;  /* distance between image and title */
  int spacing;       /* vertical space between nodes */
  int border_width;
  int mark_mode, mark_start_id;
  int show_dragdrop;
  int last_add_id;
  int show_toggle;
  int auto_redraw;
  int empty_toggle;
  int toggle_size;
  int button_size;
  int extratext_width;
  int extratext_move;
};


/********************** Additional images **********************/


static Ihandle* load_image_plus(void)
{
  unsigned char imgdata[] = {
    186, 187, 188, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 186, 187, 188,
    145, 145, 145, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 145, 145, 145,
    145, 145, 145, 252, 252, 252, 252, 252, 252, 252, 252, 252, 41, 66, 114, 252, 252, 252, 252, 252, 252, 252, 252, 252, 145, 145, 145,
    145, 145, 145, 250, 251, 251, 250, 251, 251, 250, 251, 251, 41, 66, 114, 250, 251, 251, 250, 251, 251, 250, 251, 251, 145, 145, 145,
    145, 145, 145, 250, 251, 251, 75, 99, 167, 75, 99, 167, 75, 99, 167, 75, 99, 167, 75, 99, 167, 250, 251, 251, 145, 145, 145,
    145, 145, 145, 237, 237, 236, 237, 237, 236, 237, 237, 236, 41, 66, 114, 237, 237, 236, 237, 237, 236, 237, 237, 236, 145, 145, 145,
    145, 145, 145, 227, 227, 227, 227, 227, 227, 227, 227, 227, 41, 66, 114, 227, 227, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145,
    145, 145, 145, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145,
    186, 187, 188, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 186, 187, 188 };

  Ihandle* image = IupImageRGB(9, 9, imgdata);
  return image;
}

static Ihandle* load_image_minus(void)
{
  unsigned char imgdata[] = {
    186, 187, 188, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 186, 187, 188,
    145, 145, 145, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 145, 145, 145,
    145, 145, 145, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 145, 145, 145,
    145, 145, 145, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 250, 251, 251, 145, 145, 145,
    145, 145, 145, 237, 237, 236, 75, 99, 167, 75, 99, 167, 75, 99, 167, 75, 99, 167, 75, 99, 167, 237, 237, 236, 145, 145, 145,
    145, 145, 145, 237, 237, 236, 237, 237, 236, 237, 237, 236, 237, 237, 236, 237, 237, 236, 237, 237, 236, 237, 237, 236, 145, 145, 145,
    145, 145, 145, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145,
    145, 145, 145, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145,
    186, 187, 188, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 186, 187, 188 };

  Ihandle* image = IupImageRGB(9, 9, imgdata);
  return image;
}

static Ihandle* load_image_imgcollapsed24(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 186, 178, 150, 113, 174, 165, 143, 255, 172, 164, 142, 255, 170, 162, 139, 255, 168, 159, 137, 255, 166, 156, 134, 255, 164, 153, 131, 255, 161, 150, 128, 255, 160, 148, 126, 255, 192, 184, 153, 124, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 173, 165, 143, 255, 254, 249, 195, 255, 254, 249, 196, 255, 254, 249, 196, 255, 254, 249, 196, 255, 254, 249, 196, 255, 254, 249, 196, 255, 254, 249, 196, 255, 251, 245, 193, 255, 189, 180, 152, 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, 172, 163, 141, 255, 251, 244, 177, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 240, 174, 255, 250, 242, 169, 255, 189, 180, 152, 255, 167, 157, 135, 255, 163, 153, 130, 255, 159, 148, 125, 255, 155, 144, 121, 255, 152, 140, 117, 255, 148, 134, 112, 255, 145, 130, 107, 255, 142, 128, 104, 255, 163, 145, 98, 135, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 170, 162, 139, 255, 247, 240, 171, 255, 247, 237, 165, 255, 246, 232, 150, 255, 245, 223, 130, 255, 243, 214, 108, 255, 242, 205, 84, 255, 241, 195, 61, 255, 238, 187, 39, 255, 172, 164, 143, 255, 251, 242, 181, 255, 250, 240, 177, 255, 250, 238, 173, 255, 250, 236, 167, 255, 250, 234, 162, 255, 249, 232, 157, 255, 249, 230, 152, 255, 186, 155, 62, 255, 124, 109, 84, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 167, 158, 136, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 172, 164, 143, 255, 251, 242, 182, 255, 246, 228, 141, 255, 245, 223, 130, 255, 245, 219, 119, 255, 243, 215, 109, 255, 242, 210, 97, 255, 242, 206, 85, 255, 241, 200, 73, 255, 181, 150, 59, 255, 110, 93, 76, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 158, 149, 130, 255, 247, 240, 186, 255, 251, 246, 192, 255, 251, 246, 192, 255, 251, 246, 192, 255, 251, 246, 192, 255, 251, 245, 189, 255, 251, 244, 186, 255, 251, 242, 182, 255, 245, 228, 141, 255, 245, 224, 131, 255, 244, 220, 121, 255, 243, 215, 109, 255, 243, 210, 98, 255, 242, 206, 86, 255, 241, 201, 74, 255, 240, 196, 63, 255, 176, 146, 56, 255, 94, 82, 71, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 155, 147, 128, 255, 238, 228, 158, 255, 247, 240, 171, 255, 247, 240, 171, 255, 247, 240, 171, 255, 246, 238, 166, 255, 247, 235, 160, 255, 246, 232, 151, 255, 245, 228, 142, 255, 245, 224, 133, 255, 244, 220, 122, 255, 244, 216, 110, 255, 243, 211, 99, 255, 243, 206, 87, 255, 241, 201, 75, 255, 241, 197, 64, 255, 240, 192, 53, 255, 171, 141, 53, 255, 91, 79, 67, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 152, 143, 124, 255, 235, 223, 152, 255, 247, 240, 171, 255, 247, 240, 171, 255, 247, 238, 167, 255, 246, 235, 160, 255, 246, 232, 153, 255, 245, 229, 143, 255, 244, 225, 133, 255, 245, 221, 123, 255, 244, 216, 111, 255, 243, 212, 99, 255, 242, 207, 88, 255, 241, 202, 76, 255, 241, 197, 65, 255, 240, 193, 54, 255, 238, 188, 44, 255, 167, 137, 49, 255, 88, 76, 64, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 148, 139, 121, 255, 230, 216, 144, 255, 247, 240, 171, 255, 247, 238, 167, 255, 246, 235, 160, 255, 246, 233, 153, 255, 245, 229, 144, 255, 244, 225, 134, 255, 245, 221, 123, 255, 244, 217, 112, 255, 243, 212, 101, 255, 242, 208, 89, 255, 242, 202, 77, 255, 241, 198, 66, 255, 240, 193, 55, 255, 239, 189, 44, 255, 238, 184, 34, 255, 163, 133, 47, 255, 85, 73, 62, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 144, 135, 117, 255, 225, 207, 135, 255, 247, 239, 168, 255, 246, 236, 162, 255, 246, 233, 154, 255, 246, 230, 145, 255, 245, 226, 135, 255, 244, 221, 124, 255, 244, 217, 114, 255, 243, 213, 102, 255, 243, 208, 90, 255, 242, 203, 79, 255, 241, 198, 67, 255, 240, 193, 55, 255, 239, 188, 45, 255, 238, 184, 35, 255, 237, 181, 26, 255, 159, 130, 45, 255, 82, 70, 59, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 141, 132, 114, 255, 219, 198, 125, 255, 247, 236, 162, 255, 246, 233, 154, 255, 246, 230, 146, 255, 245, 225, 136, 255, 244, 222, 126, 255, 244, 218, 115, 255, 243, 213, 104, 255, 242, 208, 91, 255, 242, 204, 80, 255, 240, 198, 68, 255, 240, 194, 57, 255, 239, 189, 47, 255, 239, 185, 36, 255, 237, 181, 27, 255, 236, 177, 19, 255, 156, 127, 43, 255, 80, 68, 57, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 136, 128, 110, 255, 215, 191, 118, 255, 246, 234, 155, 255, 245, 230, 147, 255, 245, 226, 137, 255, 245, 222, 127, 255, 244, 218, 116, 255, 243, 213, 104, 255, 242, 209, 93, 255, 241, 204, 80, 255, 241, 199, 70, 255, 241, 194, 58, 255, 239, 190, 47, 255, 239, 186, 37, 255, 238, 181, 28, 255, 236, 177, 19, 255, 235, 174, 12, 255, 155, 126, 42, 255, 77, 65, 55, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 133, 123, 107, 255, 211, 186, 112, 255, 246, 230, 148, 255, 245, 227, 138, 255, 245, 223, 127, 255, 244, 218, 116, 255, 243, 213, 106, 255, 242, 209, 94, 255, 242, 204, 82, 255, 241, 199, 70, 255, 240, 195, 59, 255, 239, 190, 48, 255, 238, 185, 38, 255, 238, 181, 29, 255, 237, 177, 20, 255, 235, 175, 13, 255, 234, 171, 8, 255, 155, 126, 42, 255, 76, 64, 54, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 129, 119, 103, 255, 211, 186, 112, 255, 245, 228, 139, 255, 244, 223, 129, 255, 244, 219, 118, 255, 243, 214, 106, 255, 242, 210, 95, 255, 242, 205, 83, 255, 241, 200, 72, 255, 240, 196, 60, 255, 240, 190, 49, 255, 239, 186, 38, 255, 238, 182, 29, 255, 236, 179, 21, 255, 235, 174, 14, 255, 234, 172, 8, 255, 233, 169, 3, 255, 155, 126, 42, 255, 76, 64, 54, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 125, 114, 99, 255, 211, 186, 112, 255, 244, 223, 130, 255, 244, 219, 119, 255, 243, 215, 108, 255, 243, 209, 96, 255, 242, 205, 85, 255, 241, 200, 72, 255, 240, 196, 61, 255, 240, 191, 51, 255, 238, 187, 40, 255, 238, 182, 30, 255, 237, 179, 22, 255, 236, 175, 14, 255, 234, 172, 8, 255, 233, 169, 4, 255, 232, 167, 1, 255, 155, 126, 42, 255, 76, 64, 54, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 112, 102, 87, 255, 213, 180, 80, 255, 210, 177, 78, 255, 207, 174, 76, 255, 201, 170, 72, 255, 196, 164, 68, 255, 190, 159, 65, 255, 185, 153, 62, 255, 178, 148, 58, 255, 173, 142, 53, 255, 167, 137, 50, 255, 163, 133, 47, 255, 159, 129, 44, 255, 155, 126, 42, 255, 155, 126, 42, 255, 155, 126, 42, 255, 155, 126, 42, 255, 155, 126, 42, 255, 76, 64, 54, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 108, 98, 84, 255, 106, 94, 82, 255, 102, 92, 79, 255, 100, 89, 76, 255, 97, 86, 73, 255, 94, 83, 71, 255, 93, 81, 69, 255, 90, 79, 67, 255, 88, 76, 64, 255, 85, 74, 62, 255, 83, 72, 60, 255, 82, 70, 59, 255, 80, 68, 57, 255, 78, 66, 56, 255, 77, 65, 55, 255, 76, 64, 54, 255, 76, 64, 54, 255, 76, 64, 54, 255, 76, 64, 54, 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, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 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(24, 24, imgdata);
  return image;
}

static Ihandle* load_image_imgexpanded24(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, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 202, 194, 159, 127, 174, 165, 143, 255, 172, 164, 142, 255, 170, 162, 139, 255, 168, 159, 137, 255, 166, 156, 134, 255, 164, 153, 131, 255, 161, 150, 128, 255, 160, 148, 126, 255, 192, 184, 153, 124, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 173, 165, 143, 255, 252, 246, 178, 255, 252, 246, 180, 255, 252, 246, 180, 255, 252, 246, 180, 255, 252, 246, 180, 255, 252, 246, 180, 255, 253, 247, 180, 255, 246, 238, 174, 255, 189, 180, 152, 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, 172, 163, 141, 255, 251, 244, 177, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 240, 174, 255, 250, 242, 169, 255, 237, 227, 159, 255, 167, 157, 135, 255, 163, 153, 130, 255, 159, 148, 125, 255, 155, 144, 121, 255, 152, 140, 117, 255, 148, 134, 112, 255, 145, 130, 107, 255, 142, 128, 104, 255, 163, 145, 98, 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, 170, 162, 139, 255, 249, 241, 175, 255, 248, 243, 179, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 241, 174, 255, 247, 237, 168, 255, 246, 235, 160, 255, 248, 233, 154, 255, 253, 235, 149, 255, 252, 234, 145, 255, 252, 234, 142, 255, 252, 230, 132, 255, 254, 228, 117, 255, 255, 225, 111, 255, 255, 224, 104, 255, 236, 204, 98, 255, 132, 115, 86, 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, 167, 158, 136, 255, 248, 240, 172, 255, 249, 243, 179, 255, 248, 242, 178, 255, 248, 242, 178, 255, 248, 240, 172, 255, 247, 236, 164, 255, 246, 233, 155, 255, 245, 229, 145, 255, 244, 225, 135, 255, 245, 220, 126, 255, 244, 219, 119, 255, 244, 217, 116, 255, 241, 210, 101, 255, 235, 197, 83, 255, 232, 195, 83, 255, 230, 189, 73, 255, 227, 184, 66, 255, 113, 95, 76, 208, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 166, 156, 134, 255, 247, 238, 170, 255, 249, 243, 180, 255, 248, 242, 179, 255, 247, 237, 169, 255, 244, 228, 152, 255, 242, 221, 137, 255, 242, 219, 128, 255, 242, 216, 118, 255, 242, 213, 109, 255, 241, 207, 95, 255, 240, 202, 85, 255, 244, 202, 71, 255, 200, 167, 80, 255, 169, 153, 115, 255, 154, 142, 105, 255, 150, 138, 101, 255, 149, 136, 97, 255, 152, 136, 94, 255, 156, 137, 93, 255, 154, 134, 90, 255, 153, 136, 88, 255, 132, 111, 75, 124, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 163, 153, 131, 255, 245, 236, 169, 255, 249, 244, 180, 255, 247, 237, 168, 255, 240, 223, 150, 255, 210, 194, 142, 255, 180, 169, 133, 255, 174, 164, 127, 255, 171, 159, 122, 255, 168, 154, 116, 255, 164, 148, 109, 255, 160, 145, 104, 255, 153, 136, 93, 255, 187, 169, 119, 255, 253, 221, 124, 255, 253, 221, 124, 255, 253, 221, 124, 255, 253, 221, 124, 255, 253, 221, 124, 255, 247, 215, 121, 255, 247, 216, 121, 255, 247, 215, 121, 255, 127, 104, 72, 255, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 161, 150, 128, 255, 244, 234, 168, 255, 249, 242, 172, 255, 245, 229, 150, 255, 211, 195, 137, 255, 213, 202, 154, 255, 242, 234, 164, 255, 240, 232, 163, 255, 240, 232, 163, 255, 240, 232, 163, 255, 240, 232, 163, 255, 240, 232, 163, 255, 241, 233, 163, 255, 244, 236, 166, 255, 255, 211, 97, 255, 250, 202, 91, 255, 249, 200, 88, 255, 246, 197, 83, 255, 245, 193, 78, 255, 244, 190, 74, 255, 244, 188, 67, 255, 205, 141, 31, 255, 154, 118, 58, 241, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 159, 148, 125, 255, 244, 231, 161, 255, 247, 233, 154, 255, 233, 212, 132, 255, 172, 164, 138, 255, 234, 222, 161, 255, 255, 229, 136, 255, 255, 217, 110, 255, 255, 217, 108, 255, 255, 217, 109, 255, 255, 217, 109, 255, 255, 215, 106, 255, 255, 213, 104, 255, 253, 211, 99, 255, 250, 204, 95, 255, 248, 202, 90, 255, 248, 199, 85, 255, 245, 196, 82, 255, 244, 193, 78, 255, 243, 189, 73, 255, 236, 172, 45, 255, 191, 141, 51, 255, 129, 100, 59, 156, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 156, 145, 122, 255, 241, 227, 153, 255, 245, 223, 132, 255, 211, 190, 123, 255, 204, 196, 154, 255, 251, 234, 155, 255, 254, 220, 123, 255, 255, 216, 111, 255, 255, 216, 111, 255, 255, 216, 111, 255, 254, 214, 108, 255, 252, 211, 105, 255, 251, 209, 101, 255, 251, 207, 96, 255, 248, 202, 91, 255, 247, 199, 86, 255, 246, 196, 81, 255, 244, 192, 78, 255, 243, 190, 74, 255, 241, 186, 65, 255, 236, 172, 45, 255, 127, 104, 72, 255, 145, 111, 55, 81, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 155, 143, 120, 255, 237, 220, 141, 255, 231, 205, 116, 255, 172, 164, 138, 255, 231, 221, 162, 255, 255, 229, 141, 255, 255, 217, 113, 255, 255, 216, 110, 255, 255, 216, 111, 255, 255, 214, 109, 255, 254, 212, 105, 255, 251, 210, 101, 255, 251, 205, 96, 255, 249, 202, 91, 255, 247, 200, 86, 255, 246, 195, 83, 255, 245, 192, 78, 255, 243, 190, 74, 255, 241, 187, 69, 255, 236, 172, 45, 255, 208, 152, 47, 255, 126, 97, 57, 196, 160, 119, 49, 2, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 153, 140, 117, 255, 233, 211, 127, 255, 212, 189, 118, 255, 196, 188, 148, 255, 252, 236, 158, 255, 253, 220, 123, 255, 255, 216, 110, 255, 255, 216, 111, 255, 254, 214, 109, 255, 252, 212, 105, 255, 251, 210, 101, 255, 251, 207, 97, 255, 250, 202, 92, 255, 246, 199, 87, 255, 246, 195, 82, 255, 244, 192, 78, 255, 243, 190, 75, 255, 242, 186, 69, 255, 238, 183, 62, 255, 236, 172, 45, 255, 127, 104, 72, 255, 141, 107, 50, 95, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 150, 137, 114, 255, 226, 200, 120, 255, 172, 164, 138, 255, 228, 219, 160, 255, 253, 228, 140, 255, 255, 216, 113, 255, 255, 216, 110, 255, 254, 215, 109, 255, 252, 212, 106, 255, 251, 210, 101, 255, 251, 207, 98, 255, 250, 202, 93, 255, 248, 200, 88, 255, 246, 197, 83, 255, 244, 192, 79, 255, 243, 190, 74, 255, 242, 187, 71, 255, 240, 183, 64, 255, 236, 172, 45, 255, 211, 154, 45, 255, 133, 101, 54, 218, 150, 111, 47, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 148, 134, 112, 255, 203, 184, 128, 255, 195, 185, 142, 255, 248, 231, 155, 255, 255, 220, 123, 255, 255, 216, 110, 255, 255, 215, 110, 255, 254, 212, 107, 255, 251, 211, 101, 255, 251, 207, 98, 255, 250, 202, 93, 255, 247, 200, 89, 255, 245, 197, 83, 255, 244, 194, 79, 255, 243, 190, 75, 255, 242, 187, 70, 255, 240, 184, 64, 255, 236, 179, 57, 255, 236, 172, 45, 255, 165, 123, 48, 255, 133, 101, 51, 105, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 145, 132, 109, 255, 172, 164, 138, 255, 225, 214, 156, 255, 255, 233, 145, 255, 255, 218, 115, 255, 255, 216, 110, 255, 254, 215, 108, 255, 254, 212, 105, 255, 252, 210, 99, 255, 251, 204, 95, 255, 249, 202, 89, 255, 247, 198, 84, 255, 245, 195, 80, 255, 244, 192, 76, 255, 244, 189, 72, 255, 242, 185, 64, 255, 237, 181, 57, 255, 236, 172, 45, 255, 205, 141, 31, 255, 127, 104, 72, 255, 139, 105, 49, 39, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 144, 129, 107, 255, 168, 156, 115, 255, 193, 164, 89, 255, 193, 164, 89, 255, 192, 164, 88, 255, 191, 162, 87, 255, 189, 160, 85, 255, 186, 157, 83, 255, 184, 155, 81, 255, 182, 152, 79, 255, 178, 149, 76, 255, 176, 146, 74, 255, 173, 144, 72, 255, 170, 141, 69, 255, 167, 138, 67, 255, 165, 136, 64, 255, 163, 133, 62, 255, 160, 130, 60, 255, 127, 104, 72, 255, 122, 93, 51, 146, 154, 113, 42, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 142, 127, 105, 255, 145, 134, 116, 255, 141, 130, 113, 255, 136, 124, 108, 255, 129, 119, 103, 255, 123, 112, 97, 255, 116, 105, 91, 255, 110, 99, 85, 255, 104, 93, 80, 255, 98, 87, 74, 255, 91, 80, 68, 255, 84, 73, 62, 255, 78, 67, 57, 255, 73, 62, 52, 255, 69, 58, 49, 255, 68, 57, 48, 255, 68, 57, 48, 255, 68, 57, 48, 255, 118, 92, 48, 165, 145, 108, 46, 54, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 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(27, 24, imgdata);
  return image;
}

static Ihandle* load_image_imgempty24(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 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(24, 24, imgdata);
  return image;
}

static Ihandle* load_image_imgleaf24(void)
{
  unsigned char imgdata[] = {
    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, 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,
    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, 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,
    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, 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,
    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, 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,
    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, 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,
    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, 173, 173, 173, 52, 168, 168, 168, 128, 163, 163, 163, 154, 157, 157, 157, 171, 150, 150, 150, 171, 142, 142, 142, 154, 133, 133, 133, 128, 124, 124, 124, 52, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 103, 167, 167, 167, 197, 160, 160, 160, 215, 158, 158, 158, 221, 156, 156, 156, 236, 144, 144, 144, 236, 126, 126, 126, 208, 120, 120, 120, 192, 114, 114, 114, 197, 106, 106, 106, 103, 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, 0, 0, 0, 0, 173, 173, 173, 103, 167, 167, 167, 202, 163, 163, 163, 211, 177, 177, 177, 255, 182, 182, 182, 255, 177, 177, 177, 255, 166, 166, 166, 255, 149, 149, 149, 255, 128, 128, 128, 255, 95, 95, 95, 220, 96, 96, 96, 202, 87, 87, 87, 103, 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, 173, 173, 173, 52, 167, 167, 167, 197, 160, 160, 160, 220, 183, 183, 183, 255, 193, 193, 193, 255, 196, 196, 196, 255, 190, 190, 190, 255, 178, 178, 178, 255, 161, 161, 161, 255, 140, 140, 140, 255, 117, 117, 117, 255, 84, 84, 84, 216, 78, 78, 78, 197, 71, 71, 71, 52, 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, 169, 169, 169, 128, 157, 157, 157, 210, 170, 170, 170, 255, 188, 188, 188, 255, 197, 197, 197, 255, 203, 203, 203, 255, 196, 196, 196, 255, 182, 182, 182, 255, 166, 166, 166, 255, 145, 145, 145, 255, 121, 121, 121, 255, 96, 96, 96, 255, 71, 71, 71, 192, 62, 62, 62, 128, 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, 163, 163, 163, 154, 149, 149, 149, 218, 170, 170, 170, 255, 186, 186, 186, 255, 194, 194, 194, 255, 197, 197, 197, 255, 193, 193, 193, 255, 180, 180, 180, 255, 164, 164, 164, 255, 143, 143, 143, 255, 121, 121, 121, 255, 98, 98, 98, 255, 67, 67, 67, 218, 55, 55, 55, 192, 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, 157, 157, 157, 171, 142, 142, 142, 236, 165, 165, 165, 255, 178, 178, 178, 255, 186, 186, 186, 255, 188, 188, 188, 255, 183, 183, 183, 255, 172, 172, 172, 255, 157, 157, 157, 255, 138, 138, 138, 255, 117, 117, 117, 255, 96, 96, 96, 255, 71, 71, 71, 236, 49, 49, 49, 237, 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, 149, 149, 149, 171, 132, 132, 132, 236, 152, 152, 152, 255, 166, 166, 166, 255, 172, 172, 172, 255, 173, 173, 173, 255, 170, 170, 170, 255, 159, 159, 159, 255, 145, 145, 145, 255, 128, 128, 128, 255, 110, 110, 110, 255, 89, 89, 89, 255, 68, 68, 68, 236, 43, 43, 43, 237, 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, 142, 142, 142, 154, 123, 123, 123, 221, 137, 137, 137, 255, 148, 148, 148, 255, 154, 154, 154, 255, 155, 155, 155, 255, 151, 151, 151, 255, 143, 143, 143, 255, 130, 130, 130, 255, 116, 116, 116, 255, 99, 99, 99, 255, 82, 82, 82, 255, 55, 55, 55, 221, 39, 39, 39, 192, 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, 133, 133, 133, 128, 117, 117, 117, 222, 115, 115, 115, 255, 129, 129, 129, 255, 134, 134, 134, 255, 135, 135, 135, 255, 132, 132, 132, 255, 124, 124, 124, 255, 114, 114, 114, 255, 102, 102, 102, 255, 87, 87, 87, 255, 70, 70, 70, 255, 44, 44, 44, 192, 39, 39, 39, 103, 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, 124, 124, 52, 114, 114, 114, 197, 95, 95, 95, 220, 105, 105, 105, 255, 112, 112, 112, 255, 115, 115, 115, 255, 112, 112, 112, 255, 106, 106, 106, 255, 97, 97, 97, 255, 86, 86, 86, 255, 73, 73, 73, 255, 51, 51, 51, 223, 40, 40, 40, 197, 39, 39, 39, 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, 106, 106, 106, 103, 95, 95, 95, 202, 81, 81, 81, 223, 88, 88, 88, 255, 92, 92, 92, 255, 90, 90, 90, 255, 86, 86, 86, 255, 79, 79, 79, 255, 69, 69, 69, 255, 51, 51, 51, 223, 40, 40, 40, 202, 39, 39, 39, 103, 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, 0, 0, 0, 0, 88, 88, 88, 103, 78, 78, 78, 197, 68, 68, 68, 210, 63, 63, 63, 228, 66, 66, 66, 236, 64, 64, 64, 236, 52, 52, 52, 225, 43, 43, 43, 192, 40, 40, 40, 197, 39, 39, 39, 103, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 70, 70, 42, 63, 63, 63, 103, 55, 55, 55, 192, 49, 49, 49, 237, 43, 43, 43, 237, 39, 39, 39, 192, 39, 39, 39, 103, 39, 39, 39, 42, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 };

  Ihandle* image = IupImageRGBA(24, 24, imgdata);
  return image;
}

static Ihandle* load_image_imgblank24(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, 166, 180, 199, 255, 161, 175, 195, 255, 160, 174, 194, 255, 159, 172, 192, 255, 156, 171, 191, 255, 155, 169, 189, 255, 154, 167, 188, 255, 151, 166, 187, 255, 149, 164, 184, 255, 143, 157, 178, 255, 141, 155, 176, 255, 132, 148, 169, 255, 76, 96, 121, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 164, 177, 197, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 145, 167, 255, 110, 127, 150, 255, 76, 96, 121, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 161, 175, 194, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 126, 142, 165, 255, 237, 239, 243, 255, 93, 112, 136, 255, 76, 96, 121, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 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, 171, 191, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 254, 255, 254, 254, 255, 255, 124, 140, 162, 255, 211, 218, 227, 255, 188, 197, 213, 255, 76, 96, 121, 255, 62, 82, 108, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 155, 169, 188, 255, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 254, 254, 255, 255, 253, 253, 254, 255, 251, 253, 254, 255, 121, 137, 160, 255, 189, 197, 213, 255, 165, 177, 199, 255, 146, 161, 185, 255, 62, 82, 108, 255, 53, 73, 99, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 150, 165, 185, 255, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 255, 255, 253, 254, 255, 255, 252, 252, 254, 255, 251, 252, 254, 255, 249, 250, 254, 255, 118, 135, 158, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 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, 147, 161, 181, 255, 251, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 255, 255, 252, 253, 254, 255, 251, 252, 254, 255, 249, 251, 253, 255, 248, 250, 253, 255, 247, 249, 253, 255, 245, 248, 253, 255, 169, 180, 201, 255, 151, 165, 189, 255, 137, 153, 178, 255, 120, 138, 164, 255, 53, 73, 99, 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, 142, 158, 178, 255, 249, 251, 253, 255, 255, 255, 255, 255, 254, 254, 255, 255, 252, 254, 255, 255, 252, 253, 254, 255, 251, 252, 254, 255, 249, 250, 254, 255, 248, 250, 253, 255, 245, 248, 253, 255, 244, 247, 252, 255, 242, 246, 252, 255, 240, 244, 252, 255, 238, 243, 252, 255, 237, 241, 251, 255, 167, 184, 218, 255, 53, 73, 99, 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, 139, 153, 174, 255, 247, 250, 253, 255, 253, 254, 255, 255, 252, 253, 254, 255, 251, 252, 255, 255, 249, 251, 253, 255, 248, 250, 253, 255, 246, 248, 253, 255, 244, 248, 253, 255, 243, 246, 252, 255, 241, 245, 252, 255, 240, 243, 252, 255, 238, 242, 251, 255, 236, 241, 251, 255, 233, 239, 250, 255, 165, 183, 216, 255, 53, 73, 99, 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, 134, 149, 171, 255, 246, 248, 253, 255, 252, 252, 254, 255, 250, 251, 254, 255, 248, 250, 254, 255, 248, 250, 253, 255, 245, 248, 253, 255, 244, 247, 253, 255, 242, 245, 252, 255, 240, 244, 252, 255, 239, 242, 251, 255, 236, 241, 251, 255, 235, 240, 251, 255, 233, 238, 249, 255, 230, 236, 249, 255, 163, 181, 216, 255, 53, 73, 99, 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, 129, 145, 167, 255, 244, 248, 252, 255, 249, 250, 254, 255, 248, 250, 253, 255, 246, 249, 253, 255, 245, 248, 253, 255, 243, 246, 252, 255, 241, 245, 252, 255, 239, 244, 251, 255, 237, 242, 251, 255, 235, 240, 251, 255, 233, 239, 250, 255, 231, 237, 250, 255, 229, 235, 250, 255, 227, 234, 249, 255, 162, 179, 215, 255, 53, 73, 99, 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, 125, 141, 164, 255, 242, 246, 252, 255, 247, 249, 253, 255, 245, 248, 253, 255, 244, 247, 252, 255, 242, 245, 252, 255, 240, 243, 251, 255, 238, 243, 251, 255, 236, 241, 251, 255, 234, 240, 251, 255, 232, 238, 250, 255, 230, 237, 250, 255, 228, 235, 248, 255, 226, 232, 248, 255, 223, 231, 248, 255, 159, 178, 214, 255, 53, 73, 99, 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, 120, 136, 159, 255, 240, 244, 251, 255, 244, 248, 253, 255, 242, 245, 252, 255, 241, 244, 252, 255, 239, 243, 252, 255, 237, 242, 251, 255, 235, 240, 250, 255, 233, 239, 250, 255, 231, 237, 250, 255, 228, 236, 249, 255, 227, 234, 249, 255, 224, 232, 248, 255, 222, 230, 248, 255, 220, 228, 248, 255, 157, 177, 214, 255, 53, 73, 99, 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, 116, 132, 155, 255, 238, 243, 251, 255, 242, 245, 252, 255, 240, 244, 252, 255, 238, 242, 251, 255, 237, 241, 250, 255, 234, 239, 250, 255, 232, 237, 250, 255, 230, 236, 249, 255, 228, 234, 249, 255, 225, 233, 248, 255, 223, 231, 248, 255, 221, 229, 248, 255, 219, 228, 246, 255, 216, 226, 247, 255, 155, 175, 213, 255, 53, 73, 99, 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, 111, 128, 151, 255, 236, 241, 250, 255, 239, 243, 251, 255, 237, 241, 251, 255, 235, 240, 251, 255, 233, 238, 250, 255, 230, 237, 250, 255, 229, 235, 249, 255, 226, 233, 248, 255, 224, 231, 248, 255, 222, 230, 247, 255, 220, 228, 247, 255, 218, 227, 247, 255, 215, 225, 246, 255, 213, 223, 246, 255, 153, 173, 212, 255, 53, 73, 99, 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, 106, 124, 147, 255, 234, 239, 250, 255, 235, 240, 250, 255, 234, 239, 250, 255, 231, 238, 250, 255, 230, 236, 249, 255, 228, 234, 249, 255, 225, 233, 248, 255, 223, 231, 247, 255, 220, 229, 247, 255, 219, 227, 246, 255, 217, 226, 246, 255, 214, 224, 246, 255, 211, 223, 245, 255, 209, 220, 245, 255, 151, 171, 212, 255, 53, 73, 99, 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, 101, 120, 143, 255, 232, 238, 250, 255, 233, 238, 250, 255, 231, 237, 250, 255, 228, 235, 249, 255, 226, 233, 248, 255, 224, 231, 248, 255, 221, 230, 247, 255, 219, 228, 247, 255, 217, 227, 247, 255, 215, 225, 246, 255, 213, 223, 246, 255, 210, 221, 245, 255, 208, 220, 244, 255, 206, 218, 243, 255, 150, 170, 211, 255, 53, 73, 99, 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, 97, 115, 139, 255, 229, 236, 249, 255, 230, 236, 250, 255, 227, 235, 248, 255, 225, 232, 248, 255, 223, 231, 248, 255, 221, 229, 247, 255, 219, 228, 247, 255, 216, 226, 247, 255, 214, 224, 246, 255, 212, 222, 245, 255, 209, 220, 244, 255, 207, 219, 245, 255, 204, 217, 244, 255, 202, 215, 243, 255, 147, 168, 210, 255, 53, 73, 99, 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, 92, 110, 134, 255, 228, 235, 249, 255, 226, 233, 248, 255, 224, 231, 248, 255, 222, 230, 248, 255, 219, 228, 247, 255, 217, 226, 247, 255, 215, 225, 246, 255, 213, 223, 245, 255, 210, 221, 245, 255, 208, 219, 244, 255, 206, 218, 244, 255, 204, 217, 243, 255, 202, 215, 243, 255, 199, 213, 242, 255, 146, 167, 210, 255, 53, 73, 99, 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, 88, 106, 131, 255, 213, 224, 245, 255, 158, 177, 213, 255, 156, 176, 213, 255, 154, 174, 212, 255, 153, 172, 212, 255, 151, 172, 212, 255, 150, 171, 211, 255, 148, 169, 210, 255, 147, 168, 209, 255, 145, 166, 209, 255, 140, 162, 207, 255, 138, 161, 206, 255, 138, 161, 206, 255, 136, 159, 206, 255, 136, 159, 205, 255, 53, 73, 99, 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, 84, 102, 127, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 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 };

  Ihandle* image = IupImageRGBA(24, 24, imgdata);
  return image;
}

static Ihandle* load_image_imgpaper24(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, 166, 180, 199, 255, 161, 175, 195, 255, 160, 174, 194, 255, 159, 172, 192, 255, 156, 171, 191, 255, 155, 169, 189, 255, 154, 167, 188, 255, 151, 166, 187, 255, 149, 164, 184, 255, 143, 157, 178, 255, 141, 155, 176, 255, 132, 148, 169, 255, 53, 73, 99, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 164, 177, 197, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 145, 167, 255, 110, 127, 150, 255, 53, 73, 99, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 161, 175, 194, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 126, 142, 165, 255, 237, 239, 243, 255, 93, 112, 136, 255, 76, 96, 121, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 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, 171, 191, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 254, 255, 254, 254, 255, 255, 124, 140, 162, 255, 211, 218, 227, 255, 188, 197, 213, 255, 76, 96, 121, 255, 62, 82, 108, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 155, 169, 188, 255, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 254, 254, 255, 255, 253, 253, 254, 255, 251, 253, 254, 255, 121, 137, 160, 255, 189, 197, 213, 255, 165, 177, 199, 255, 146, 161, 185, 255, 62, 82, 108, 255, 53, 73, 99, 102, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 150, 165, 185, 255, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 255, 255, 253, 254, 255, 255, 252, 252, 254, 255, 251, 252, 254, 255, 249, 250, 254, 255, 118, 135, 158, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 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, 147, 161, 181, 255, 251, 252, 254, 255, 255, 255, 255, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 247, 249, 253, 255, 245, 248, 253, 255, 169, 180, 201, 255, 151, 165, 189, 255, 137, 153, 178, 255, 120, 138, 164, 255, 53, 73, 99, 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, 142, 158, 178, 255, 249, 251, 253, 255, 255, 255, 255, 255, 254, 254, 255, 255, 252, 254, 255, 255, 252, 253, 254, 255, 251, 252, 254, 255, 249, 250, 254, 255, 248, 250, 253, 255, 245, 248, 253, 255, 244, 247, 252, 255, 242, 246, 252, 255, 240, 244, 252, 255, 238, 243, 252, 255, 237, 241, 251, 255, 167, 184, 218, 255, 53, 73, 99, 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, 139, 153, 174, 255, 247, 250, 253, 255, 253, 254, 255, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 36, 75, 152, 255, 35, 71, 146, 255, 33, 68, 141, 255, 236, 241, 251, 255, 233, 239, 250, 255, 165, 183, 216, 255, 53, 73, 99, 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, 134, 149, 171, 255, 246, 248, 253, 255, 252, 252, 254, 255, 250, 251, 254, 255, 248, 250, 254, 255, 248, 250, 253, 255, 245, 248, 253, 255, 244, 247, 253, 255, 242, 245, 252, 255, 240, 244, 252, 255, 239, 242, 251, 255, 236, 241, 251, 255, 235, 240, 251, 255, 233, 238, 249, 255, 230, 236, 249, 255, 163, 181, 216, 255, 53, 73, 99, 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, 129, 145, 167, 255, 244, 248, 252, 255, 249, 250, 254, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 36, 75, 152, 255, 35, 71, 146, 255, 33, 68, 141, 255, 229, 235, 250, 255, 227, 234, 249, 255, 162, 179, 215, 255, 53, 73, 99, 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, 125, 141, 164, 255, 242, 246, 252, 255, 247, 249, 253, 255, 245, 248, 253, 255, 244, 247, 252, 255, 242, 245, 252, 255, 240, 243, 251, 255, 238, 243, 251, 255, 236, 241, 251, 255, 234, 240, 251, 255, 232, 238, 250, 255, 230, 237, 250, 255, 228, 235, 248, 255, 226, 232, 248, 255, 223, 231, 248, 255, 159, 178, 214, 255, 53, 73, 99, 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, 120, 136, 159, 255, 240, 244, 251, 255, 244, 248, 253, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 36, 75, 152, 255, 35, 71, 146, 255, 33, 68, 141, 255, 222, 230, 248, 255, 220, 228, 248, 255, 157, 177, 214, 255, 53, 73, 99, 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, 116, 132, 155, 255, 238, 243, 251, 255, 242, 245, 252, 255, 240, 244, 252, 255, 238, 242, 251, 255, 237, 241, 250, 255, 234, 239, 250, 255, 232, 237, 250, 255, 230, 236, 249, 255, 228, 234, 249, 255, 225, 233, 248, 255, 223, 231, 248, 255, 221, 229, 248, 255, 219, 228, 246, 255, 216, 226, 247, 255, 155, 175, 213, 255, 53, 73, 99, 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, 111, 128, 151, 255, 236, 241, 250, 255, 239, 243, 251, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 36, 75, 152, 255, 35, 71, 146, 255, 33, 68, 141, 255, 215, 225, 246, 255, 213, 223, 246, 255, 153, 173, 212, 255, 53, 73, 99, 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, 106, 124, 147, 255, 234, 239, 250, 255, 235, 240, 250, 255, 234, 239, 250, 255, 231, 238, 250, 255, 230, 236, 249, 255, 228, 234, 249, 255, 225, 233, 248, 255, 223, 231, 247, 255, 220, 229, 247, 255, 219, 227, 246, 255, 217, 226, 246, 255, 214, 224, 246, 255, 211, 223, 245, 255, 209, 220, 245, 255, 151, 171, 212, 255, 53, 73, 99, 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, 101, 120, 143, 255, 232, 238, 250, 255, 233, 238, 250, 255, 46, 97, 198, 255, 45, 94, 192, 255, 43, 90, 186, 255, 42, 87, 178, 255, 40, 84, 172, 255, 38, 81, 165, 255, 38, 77, 158, 255, 36, 75, 152, 255, 35, 71, 146, 255, 33, 68, 141, 255, 208, 220, 244, 255, 206, 218, 243, 255, 150, 170, 211, 255, 53, 73, 99, 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, 97, 115, 139, 255, 229, 236, 249, 255, 230, 236, 250, 255, 227, 235, 248, 255, 225, 232, 248, 255, 223, 231, 248, 255, 221, 229, 247, 255, 219, 228, 247, 255, 216, 226, 247, 255, 214, 224, 246, 255, 212, 222, 245, 255, 209, 220, 244, 255, 207, 219, 245, 255, 204, 217, 244, 255, 202, 215, 243, 255, 147, 168, 210, 255, 53, 73, 99, 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, 92, 110, 134, 255, 228, 235, 249, 255, 226, 233, 248, 255, 224, 231, 248, 255, 222, 230, 248, 255, 219, 228, 247, 255, 217, 226, 247, 255, 215, 225, 246, 255, 213, 223, 245, 255, 210, 221, 245, 255, 208, 219, 244, 255, 206, 218, 244, 255, 204, 217, 243, 255, 202, 215, 243, 255, 199, 213, 242, 255, 146, 167, 210, 255, 53, 73, 99, 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, 88, 106, 131, 255, 213, 224, 245, 255, 158, 177, 213, 255, 156, 176, 213, 255, 154, 174, 212, 255, 153, 172, 212, 255, 151, 172, 212, 255, 150, 171, 211, 255, 148, 169, 210, 255, 147, 168, 209, 255, 145, 166, 209, 255, 140, 162, 207, 255, 138, 161, 206, 255, 138, 161, 206, 255, 136, 159, 206, 255, 136, 159, 205, 255, 53, 73, 99, 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, 84, 102, 127, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 255, 53, 73, 99, 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 };

  Ihandle* image = IupImageRGBA(24, 24, imgdata);
  return image;
}

static void iFlatTreeInitializeImages(void)
{
  IupSetHandle("IMGPLUS", load_image_plus());
  IupSetHandle("IMGMINUS", load_image_minus());

  IupSetHandle("IMGEXPANDED24", load_image_imgexpanded24());
  IupSetHandle("IMGCOLLAPSED24", load_image_imgcollapsed24());
  IupSetHandle("IMGLEAF24", load_image_imgleaf24());

  IupSetHandle("IMGEMPTY24", load_image_imgempty24());
  IupSetHandle("IMGBLANK24", load_image_imgblank24());
  IupSetHandle("IMGPAPER24", load_image_imgpaper24());
}


/********************** Utilities **********************/


static int iFlatTreeFindUserDataId(Ihandle* ih, void* userdata)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i, count = iupArrayCount(ih->data->node_array);

  for (i = 0; i < count; i++)
  {
    if (nodes[i]->userdata == userdata)
      return i;
  }

  return -1;
}

static void iFlatTreeSetNodeDrawFont(Ihandle* ih, iFlatTreeNode *node, const char* font)
{
  if (node->font)
    iupAttribSet(ih, "DRAWFONT", node->font);
  else
    iupAttribSet(ih, "DRAWFONT", font);
}

static char *iFlatTreeGetNodeImage(Ihandle* ih, iFlatTreeNode *node, int check_state)
{
  char* image;

  if (node->kind == IFLATTREE_LEAF)
  {
    if (node->image)
      image = node->image;
    else
      image = iupAttribGetStr(ih, "IMAGELEAF");
  }
  else
  {
    if (!check_state || node->state == IFLATTREE_COLLAPSED)
    {
      if (node->image)
        image = node->image;
      else
        image = iupAttribGetStr(ih, "IMAGEBRANCHCOLLAPSED");
    }
    else
    {
      if (node->image_expanded)
        image = node->image_expanded;
      else
        image = iupAttribGetStr(ih, "IMAGEBRANCHEXPANDED");
    }
  }

  return image;
}


/********************** Node Hierarchy **********************/


static void iFlatTreeUpdateNodeChildExpandedRec(iFlatTreeNode *node)
{
  int expanded = node->parent->expanded && node->parent->state == IFLATTREE_EXPANDED;

  while (node)
  {
    if (node->expanded != expanded)
    {
      node->expanded = expanded;

      if (node->kind == IFLATTREE_BRANCH && node->first_child)
        iFlatTreeUpdateNodeChildExpandedRec(node->first_child);
    }

    node = node->brother;
  }
}

static void iFlatTreeUpdateNodeExpanded(iFlatTreeNode *node)
{
  node->expanded = node->parent->expanded && node->parent->state == IFLATTREE_EXPANDED;

  if (node->kind == IFLATTREE_BRANCH && node->first_child)
    iFlatTreeUpdateNodeChildExpandedRec(node->first_child);
}

static void iFlatTreeCalcNodeSize(Ihandle *ih, iFlatTreeNode *node, const char* font)
{
  int w, h;
  int img_w = 0, img_h = 0;
  int txt_w = 0, txt_h = 0;
  char *image = iFlatTreeGetNodeImage(ih, node, 0);

  iupImageGetInfo(image, &img_w, &img_h, NULL);

  iFlatTreeSetNodeDrawFont(ih, node, font);

  if (node->title)
    iupDrawGetTextSize(ih, node->title, 0, &txt_w, &txt_h, 0);
  else
    iupDrawGetTextSize(ih, "W", 0, &txt_w, &txt_h, 0);

  /* leave room for focus feedback */
  if (ih->iclass->is_interactive && iupAttribGetBoolean(ih, "CANFOCUS") && iupAttribGetBoolean(ih, "FOCUSFEEDBACK"))
  {
    txt_w += 2 * 2;
    txt_h += 2 * 2;
  }

  node->title_width = txt_w;

  w = img_w + ih->data->icon_spacing + txt_w;
  h = iupMAX(img_h, txt_h);

  node->height = h;
  node->width = w + ((node->depth + 1) * ih->data->indentation);

  if (ih->data->show_toggle && node->toggle_visible)
    node->width += ih->data->toggle_size;
}

static void iFlatTreeUpdateNodeSizeRec(Ihandle *ih, iFlatTreeNode *node, const char* font)
{
  while (node)
  {
    iFlatTreeCalcNodeSize(ih, node, font);

    if (node->kind == IFLATTREE_BRANCH && node->first_child)
      iFlatTreeUpdateNodeSizeRec(ih, node->first_child, font);

    node = node->brother;
  }
}

static void iFlatTreeUpdateNodeSize(Ihandle *ih, iFlatTreeNode *node)
{
  char* font = IupGetAttribute(ih, "FONT");
  iFlatTreeCalcNodeSize(ih, node, font);
}

static void iFlatTreeUpdateNodeSizeAll(Ihandle *ih)
{
  char* font = IupGetAttribute(ih, "FONT");
  iFlatTreeUpdateNodeSizeRec(ih, ih->data->root_node->first_child, font);
}

static void iFlatTreeUpdateNodeIdRec(iFlatTreeNode **nodes, iFlatTreeNode *node, int *id, int depth)
{
  while (node)
  {
    nodes[*id] = node;
    node->id = *id;
    node->depth = depth;
    (*id)++;

    if (node->kind == IFLATTREE_BRANCH && node->first_child)
      iFlatTreeUpdateNodeIdRec(nodes, node->first_child, id, depth + 1);

    node = node->brother;
  }
}

static void iFlatTreeRebuildArray(Ihandle *ih, int num)
{
  /* one or mode nodes were moved (num=0), removed (num<0) or added (num>0), must update all the ids */
  iFlatTreeNode *node = ih->data->root_node->first_child;
  int id = 0;
  int depth = 0;
  
  if (num > 0)
    iupArrayAdd(ih->data->node_array, num);  /* increment the array */
  else if (num < 0)
  {
    int count = iupArrayCount(ih->data->node_array);
    iupArrayRemove(ih->data->node_array, count+num, -num);  /* decrement the array, memory is preserved */
  }
  else
  {
    if (!node)
    {
      int count = iupArrayCount(ih->data->node_array);
      iupArrayRemove(ih->data->node_array, 0, count);  /* clear the array, memory is preserved */
    }
  }
  
  iFlatTreeUpdateNodeIdRec(iupArrayGetData(ih->data->node_array), node, &id, depth);
}

static iFlatTreeNode *iFlatTreeGetNode(Ihandle *ih, int id)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);

  if (id == IUP_INVALID_ID)
    id = ih->data->focus_id;

  if (id >= 0 && id < count)
    return nodes[id];
  else
    return NULL;
}

static iFlatTreeNode *iFlatTreeGetNodeFromString(Ihandle* ih, const char* name_id)
{
  int id = IUP_INVALID_ID;
  iupStrToInt(name_id, &id);
  return iFlatTreeGetNode(ih, id);
}

static int iFlatTreeGetNextExpandedNodeId(Ihandle *ih, int id)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  int i;

  if (id < 0 || id >= count)
    return 0;

  for (i = id + 1; i < count; i++)
  {
    if (nodes[i]->expanded)
      return i;
  }

  return id;
}

static int iFlatTreeGetPreviousExpandedNodeId(Ihandle *ih, int id)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  int i;

  if (id < 0 || id >= count)
    return 0;

  for (i = id - 1; i >= 0; i--)
  {
    if (nodes[i]->expanded)
      return i;
  }

  return id;
}

static int iFlatTreeGetLastExpandedNodeId(Ihandle *ih)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i;

  for (i = count - 1; i >= 0; i--)
  {
    if (nodes[i]->expanded)
      return i;
  }

  return -1;
}

static int iFlatTreeGetFirstExpandedNodeId(Ihandle *ih)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i;

  for (i = 0; i < count; i++)
  {
    if (nodes[i]->expanded)
      return i;
  }

  return -1;
}

static iFlatTreeNode *iFlatTreeNewNode(const char* title, int kind)
{
  iFlatTreeNode *newNode = (iFlatTreeNode *)malloc(sizeof(iFlatTreeNode));
  memset(newNode, 0, sizeof(iFlatTreeNode));

  newNode->title = iupStrDup(title);
  newNode->kind = kind;
  newNode->toggle_visible = 1;

  return newNode;
}

static iFlatTreeNode *iFlatTreeCloneNode(iFlatTreeNode *node)
{
  iFlatTreeNode *newNode = (iFlatTreeNode*)malloc(sizeof(iFlatTreeNode));
  memset(newNode, 0, sizeof(iFlatTreeNode));

  newNode->title = iupStrDup(node->title);
  newNode->image = iupStrDup(node->image);
  newNode->image_expanded = iupStrDup(node->image_expanded);
  newNode->bg_color = iupStrDup(node->bg_color);
  newNode->fg_color = iupStrDup(node->fg_color);
  newNode->tip = iupStrDup(node->tip);
  newNode->font = iupStrDup(node->font);
  newNode->kind = node->kind;
  newNode->state = node->state;
  newNode->toggle_visible = node->toggle_visible;
  newNode->toggle_value = node->toggle_value;
  /* selected and userdata are NOT copied */

  if (node->first_child)
  {
    iFlatTreeNode *child = node->first_child;
    iFlatTreeNode *lastNode = NULL;

    while (child)
    {
      iFlatTreeNode *newChildNode = iFlatTreeCloneNode(child);
      if (!lastNode)
        newNode->first_child = newChildNode;
      else
        lastNode->brother = newChildNode;
      newChildNode->parent = newNode;
      lastNode = newChildNode;

      child = child->brother;
    }
  }

  return newNode;
}

static void iFlatTreeUnlinkNodeFromParent(iFlatTreeNode* node)
{
  /* removed the node from its parent */
  iFlatTreeNode *parent = node->parent;
  if (node == parent->first_child)
    parent->first_child = node->brother;
  else
  {
    iFlatTreeNode *brother = parent->first_child;
    while (brother)
    {
      if (brother->brother == node)
      {
        brother->brother = node->brother;
        break;
      }

      brother = brother->brother;
    }
  }
}

static void iFlatTreeRemoveNode(Ihandle *ih, iFlatTreeNode *node, IFns noderemoved_cb)
{
  /* remove node and its children */
  iFlatTreeNode *child = node->first_child;
  while (child)
  {
    iFlatTreeNode *brother = child->brother;
    iFlatTreeRemoveNode(ih, child, noderemoved_cb);
    child = brother;
  }

  if (noderemoved_cb)
    noderemoved_cb(ih, node->userdata);

  if (node->title)
    free(node->title);

  if (node->image)
    free(node->image);

  if (node->image_expanded)
    free(node->image_expanded);

  if (node->fg_color)
    free(node->fg_color);

  if (node->bg_color)
    free(node->bg_color);

  if (node->tip)
    free(node->tip);

  if (node->font)
    free(node->font);

  free(node);
}

static int iFlatTreeGetChildCount(iFlatTreeNode *node);

static iFlatTreeNode *iFlatTreeCopyNode(Ihandle *ih, int srcId, int dstId)
{
  iFlatTreeNode *srcNode = iFlatTreeGetNode(ih, srcId);
  iFlatTreeNode *dstNode = iFlatTreeGetNode(ih, dstId);
  iFlatTreeNode *parent;
  iFlatTreeNode *newNode;
  int count;

  if (!dstNode || !srcNode)
    return NULL;

  /* If srcNode is an ancestor of dstNode then return */
  parent = dstNode;
  while (parent)
  {
    if (parent == srcNode)
      return NULL;

    parent = parent->parent;
  }

  newNode = iFlatTreeCloneNode(srcNode);
  count = iFlatTreeGetChildCount(srcNode) + 1;

  if (dstNode->kind == IFLATTREE_BRANCH && dstNode->state == IFLATTREE_EXPANDED)
  {
    /* copy as first child of expanded branch */
    newNode->parent = dstNode;
    newNode->brother = dstNode->first_child;
    dstNode->first_child = newNode;
  }
  else
  {
    newNode->parent = dstNode->parent;
    newNode->brother = dstNode->brother;
    dstNode->brother = newNode;
  }

  iFlatTreeRebuildArray(ih, +count);
  iFlatTreeUpdateNodeSize(ih, dstNode);
  iFlatTreeUpdateNodeExpanded(dstNode);

  return newNode;
}

static iFlatTreeNode *iFlatTreeMoveNode(Ihandle *ih, int srcId, int dstId)
{
  iFlatTreeNode *srcNode = iFlatTreeGetNode(ih, srcId);
  iFlatTreeNode *dstNode = iFlatTreeGetNode(ih, dstId);
  iFlatTreeNode *parent;

  if (!dstNode || !srcNode)
    return NULL;

  /* If srcNode is an ancestor of dstNode then return */
  parent = dstNode;
  while (parent)
  {
    if (parent == srcNode)
      return NULL;

    parent = parent->parent;
  }

  iFlatTreeUnlinkNodeFromParent(srcNode);

  if (dstNode->kind == IFLATTREE_BRANCH && dstNode->state == IFLATTREE_EXPANDED)
  {
    /* copy as first child of expanded branch */
    srcNode->parent = dstNode;
    srcNode->brother = dstNode->first_child;
    dstNode->first_child = srcNode;
  }
  else
  {
    srcNode->parent = dstNode->parent;
    srcNode->brother = dstNode->brother;
    dstNode->brother = srcNode;
  }

  iFlatTreeRebuildArray(ih, 0);
  iFlatTreeUpdateNodeExpanded(srcNode);

  return srcNode;
}

static void iFlatTreeAddNode(Ihandle* ih, int id, int kind, const char* title)
{
  iFlatTreeNode *refNode;
  iFlatTreeNode *newNode;
  int count;

  if (id == -1)
    refNode = ih->data->root_node;
  else
    refNode = iFlatTreeGetNode(ih, id);

  if (!refNode)
    return;

  newNode = iFlatTreeNewNode(title, kind);

  if (refNode->kind == IFLATTREE_LEAF)
  {
    /* add as brother */
    newNode->parent = refNode->parent;
    newNode->brother = refNode->brother;

    refNode->brother = newNode;
  }
  else
  {
    /* add as first child */
    newNode->parent = refNode;
    newNode->brother = refNode->first_child;

    refNode->first_child = newNode;
  }

  if (newNode->kind == IFLATTREE_BRANCH)
    newNode->state = ih->data->add_expanded ? IFLATTREE_EXPANDED : IFLATTREE_COLLAPSED;

  iFlatTreeRebuildArray(ih, +1);
  iFlatTreeUpdateNodeSize(ih, newNode);
  iFlatTreeUpdateNodeExpanded(newNode);

  ih->data->last_add_id = newNode->id;

  count = iupArrayCount(ih->data->node_array);
  if (count == 1)
  {
    /* MarkStart node */
    ih->data->mark_start_id = newNode->id;  /* same as 0 when count==1 */

    /* Set the default VALUE (focus) */
    ih->data->focus_id = newNode->id;

    /* when single selection when focus is set, node is also selected */
    if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
      newNode->selected = 1;
  }
}

static void iFlatTreeInsertNode(Ihandle* ih, int id, int kind, const char* title)
{
  iFlatTreeNode *refNode;
  iFlatTreeNode *newNode;

  if (id == -1)
    refNode = iFlatTreeGetNode(ih, 0);
  else
    refNode = iFlatTreeGetNode(ih, id);

  if (!refNode)
    return;

  newNode = iFlatTreeNewNode(title, kind);

  /* add as brother always */
  newNode->parent = refNode->parent;
  newNode->brother = refNode->brother;

  refNode->brother = newNode;

  if (newNode->kind == IFLATTREE_BRANCH)
    newNode->state = ih->data->add_expanded ? IFLATTREE_EXPANDED : IFLATTREE_COLLAPSED;

  iFlatTreeRebuildArray(ih, +1);
  iFlatTreeUpdateNodeSize(ih, newNode);
  iFlatTreeUpdateNodeExpanded(newNode);

  ih->data->last_add_id = newNode->id;
}

static int iFlatTreeConvertPosToId(Ihandle *ih, int pos)
{
  /* pos is the index of the expanded node */
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i, p = 0;

  if (pos < 0 || pos >= count)
    return -1;

  for (i = 0; i < count; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    if (p == pos)
      break;

    p++;
  }

  return i;
}

static int iFlatTreeConvertXYToId(Ihandle* ih, int x, int y)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int posy = IupGetInt(ih, "POSY");
  int node_y = 0, i;

  y += posy;

  if (y < 0)
    return -1;

  for (i = 0; i < count; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    if (y >= node_y && y < (node_y + nodes[i]->height))
      return i;

    node_y += nodes[i]->height + ih->data->spacing;
  }

  (void)x;
  return -1;
}

static int iFlatTreeGetNodeY(Ihandle *ih, iFlatTreeNode *node)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i;
  int node_y = 0;

  for (i = 0; i < node->id; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    node_y += nodes[i]->height + ih->data->spacing;
  }

  return node_y;
}

static int iFlatTreeConvertIdToY(Ihandle *ih, int id, int *h)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i;
  int node_y = 0;

  if (id < 0 || id >= count)
    return -1;

  for (i = 0; i < id; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    node_y += nodes[i]->height + ih->data->spacing;
  }

  if (h)
    *h = nodes[id]->height;

  return node_y;
}


/***********************************   Scrollbar ************************************/


static int iFlatTreeGetScrollbar(Ihandle* ih)
{
  int flat = iupFlatScrollBarGet(ih);
  if (flat != IUP_SB_NONE)
    return flat;
  else
  {
    if (!ih->handle)
      ih->data->canvas.sb = iupBaseGetScrollbar(ih);

    return ih->data->canvas.sb;
  }
}

static int iFlatTreeGetScrollbarSize(Ihandle* ih)
{
  if (iupFlatScrollBarGet(ih) != IUP_SB_NONE)
  {
    if (iupAttribGetBoolean(ih, "SHOWFLOATING"))
      return 0;
    else
      return iupAttribGetInt(ih, "SCROLLBARSIZE");
  }
  else
    return iupdrvGetScrollbarSize();
}


static void iFlatTreeGetViewSize(Ihandle *ih, int *view_width, int *view_height, int *line_height)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i;
  int total_h = 0;
  int max_w = 0;
  int j = 0;

  for (i = 0; i < count; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    total_h += nodes[i]->height + ih->data->spacing;
    max_w = (nodes[i]->width > max_w) ? nodes[i]->width : max_w;
    j++;
  }

  if (j == 0)
    *line_height = 0;
  else
    *line_height = total_h / j;

  *view_width = max_w;
  *view_height = total_h;
}

static void iFlatTreeUpdateScrollBar(Ihandle *ih)
{
  int canvas_width = ih->currentwidth;
  int canvas_height = ih->currentheight;
  int sb, view_width, view_height;
  int line_height;  /* average line height (includes spacing) */

  if (iupAttribGetBoolean(ih, "BORDER")) /* native border around scrollbars */
  {
    canvas_width -= 2;
    canvas_height -= 2;
  }

  canvas_width -= 2 * ih->data->border_width;
  canvas_height -= 2 * ih->data->border_width;

  iFlatTreeGetViewSize(ih, &view_width, &view_height, &line_height);

  if (ih->data->show_dragdrop || iupAttribGetBoolean(ih, "DRAGDROPTREE"))
    view_height += line_height/2; /* additional space for drop area */

  sb = iFlatTreeGetScrollbar(ih);
  if (sb)
  {
    int sb_size = iFlatTreeGetScrollbarSize(ih);
    int noscroll_width = canvas_width;
    int noscroll_height = canvas_height;

    if (sb & IUP_SB_HORIZ)
    {
      IupSetInt(ih, "XMAX", view_width);

      if (view_height > noscroll_height)  /* affects horizontal size */
        canvas_width -= sb_size;
    }
    else
      IupSetAttribute(ih, "XMAX", "0");

    if (sb & IUP_SB_VERT)
    {
      IupSetInt(ih, "YMAX", view_height);

      if (view_width > noscroll_width)  /* affects vertical size */
        canvas_height -= sb_size;
    }
    else
      IupSetAttribute(ih, "YMAX", "0");

    /* check again, adding a scrollbar may affect the other scrollbar need if not done already */
    if (sb & IUP_SB_HORIZ && view_height <= noscroll_height && view_height > canvas_height)
      canvas_width -= sb_size;
    if (sb & IUP_SB_VERT && view_width <= noscroll_width && view_width > canvas_width)
      canvas_height -= sb_size;

    if (canvas_width < 0) canvas_width = 0;
    if (canvas_height < 0) canvas_height = 0;

    if (sb & IUP_SB_HORIZ)
      IupSetInt(ih, "DX", canvas_width);
    else
      IupSetAttribute(ih, "DX", "0");

    if (sb & IUP_SB_VERT)
      IupSetInt(ih, "DY", canvas_height);
    else
      IupSetAttribute(ih, "DY", "0");

    IupSetfAttribute(ih, "LINEY", "%d", line_height);
  }
  else
  {
    IupSetAttribute(ih, "XMAX", "0");
    IupSetAttribute(ih, "YMAX", "0");

    IupSetAttribute(ih, "DX", "0");
    IupSetAttribute(ih, "DY", "0");
  }
}


/**************************************  Internal Callbacks  *****************************************/


static void iupFlatDrawPlus(IdrawCanvas* dc, int xmin, int xmax, int ymin, int ymax, long line_rgba, int space)
{
  int xhalf = (xmax + xmin) / 2;
  int yhalf = (ymax + ymin) / 2;
  iupdrvDrawLine(dc, xmin, yhalf,   xmax, yhalf,   line_rgba, IUP_DRAW_STROKE, 1);
  if (space == 2)
    iupdrvDrawLine(dc, xmin, yhalf+1, xmax, yhalf+1, line_rgba, IUP_DRAW_STROKE, 1);
  iupdrvDrawLine(dc, xhalf,   ymin, xhalf,   ymax, line_rgba, IUP_DRAW_STROKE, 1);
  if (space == 2)
    iupdrvDrawLine(dc, xhalf+1, ymin, xhalf+1, ymax, line_rgba, IUP_DRAW_STROKE, 1);
}

static void iupFlatDrawMinus(IdrawCanvas* dc, int xmin, int xmax, int ymin, int ymax, long line_rgba, int space)
{
  int yhalf = (ymax + ymin) / 2;
  iupdrvDrawLine(dc, xmin, yhalf,   xmax, yhalf,   line_rgba, IUP_DRAW_STROKE, 1);
  if (space == 2)
    iupdrvDrawLine(dc, xmin, yhalf+1, xmax, yhalf+1, line_rgba, IUP_DRAW_STROKE, 1);
}

static void iFlatTreeDrawExpanderButton(IdrawCanvas* dc, iFlatTreeNode *node, int x, int y, int node_h, int button_size, long border_color, long fore_color, long back_color)
{
  int check_xmin = x + 1;
  int check_ymin = y + ((node_h - button_size) / 2) + 1;
  int space = 2;

  if (button_size < 10)
  {
    space = 1;
    check_ymin--;
  }

  /* box */
  iupdrvDrawRectangle(dc, check_xmin, check_ymin,
                      check_xmin + button_size - 1, check_ymin + button_size - 1,
                      border_color, IUP_DRAW_STROKE, 1);
  check_ymin++;
  check_xmin++;
  button_size -= 2;
  iupdrvDrawRectangle(dc, check_xmin, check_ymin,
                      check_xmin + button_size - 1, check_ymin + button_size - 1,
                      back_color, IUP_DRAW_FILL, 1);

  check_ymin += space;
  check_xmin += space;
  button_size -= 2 * space;

  /* expander sign */
  if (node->state == IFLATTREE_EXPANDED)
  {
    iupFlatDrawMinus(dc, check_xmin, check_xmin + button_size - 1,
                         check_ymin, check_ymin + button_size - 1,
                         fore_color, space);
  }
  else
  {
    iupFlatDrawPlus(dc, check_xmin, check_xmin + button_size - 1,
                        check_ymin, check_ymin + button_size - 1,
                        fore_color, space);
  }
}

static void iFlatTreeDrawToggle(Ihandle *ih, IdrawCanvas* dc, iFlatTreeNode *node, int x, int y, int node_h, const char* bg_color, const char* toggle_fgcolor, const char* toggle_bgcolor, int active)
{
  int check_xmin = x + IFLATTREE_TOGGLE_MARGIN;
  int check_ymin = y + IFLATTREE_TOGGLE_MARGIN + ((node_h - ih->data->toggle_size) / 2);
  int check_size = ih->data->toggle_size - 2 * IFLATTREE_TOGGLE_MARGIN;

  /* box */
  iupFlatDrawBorder(dc, check_xmin, check_xmin + check_size,
                        check_ymin, check_ymin + check_size,
                        IFLATTREE_TOGGLE_BORDER, toggle_fgcolor, bg_color, active);
  iupFlatDrawBox(dc, check_xmin + IFLATTREE_TOGGLE_BORDER, check_xmin + check_size - IFLATTREE_TOGGLE_BORDER,
                     check_ymin + IFLATTREE_TOGGLE_BORDER, check_ymin + check_size - IFLATTREE_TOGGLE_BORDER,
                     toggle_bgcolor, bg_color, active);

  /* check mark */
  if (node->toggle_value)
  {
    if (node->toggle_value == -1)
      iupFlatDrawBox(dc, check_xmin + IFLATTREE_TOGGLE_SPACE + IFLATTREE_TOGGLE_BORDER, check_xmin + check_size - IFLATTREE_TOGGLE_SPACE - IFLATTREE_TOGGLE_BORDER,
                         check_ymin + IFLATTREE_TOGGLE_SPACE + IFLATTREE_TOGGLE_BORDER, check_ymin + check_size - IFLATTREE_TOGGLE_SPACE - IFLATTREE_TOGGLE_BORDER,
                         toggle_fgcolor, toggle_bgcolor, active);
    else
      iupFlatDrawCheckMark(dc, check_xmin + IFLATTREE_TOGGLE_SPACE + IFLATTREE_TOGGLE_BORDER, check_xmin + check_size - IFLATTREE_TOGGLE_SPACE - IFLATTREE_TOGGLE_BORDER,
                               check_ymin + IFLATTREE_TOGGLE_SPACE + IFLATTREE_TOGGLE_BORDER, check_ymin + check_size - IFLATTREE_TOGGLE_SPACE - IFLATTREE_TOGGLE_BORDER,
                               toggle_fgcolor, toggle_bgcolor, active);
  }
}

static int iFlatTreeDrawNodes(Ihandle *ih, IdrawCanvas* dc, iFlatTreeNode *node, int x, int y, const char *fg_color, const char *bg_color, long line_rgba, const char *toggle_fgcolor, const char *toggle_bgcolor, int make_inactive, int active,
                              int text_flags, const char *font, int focus_feedback, int hide_lines)
{
  int node_x = x + (node->depth * ih->data->indentation);
  int node_y = y;

  while (node)
  {
    int node_h = node->height;

    /* guidelines */
    if (node->depth != 0 && !hide_lines)
    {
      int px1 = (node_x - (ih->data->indentation / 2)) + 1;
      int py1 = node_y + node_h / 2;
      int px2 = node_x;
      int py2 = py1;  /* horizontal line */
      if (py1 > 0 && py1 < ih->currentheight)
        iupdrvDrawLine(dc, px1, py1, px2, py2, line_rgba, IUP_DRAW_STROKE_DOT, 1);

      if (!node->brother)  /* on the last child draw the vertical line */
      {
        px1 = node_x - (ih->data->indentation / 2);
        py1 = y - ih->data->spacing;
        px2 = px1;   /* vertical line */
        py2 = node_y + node_h / 2;
        if ((py1 >= 0 && py1 < ih->currentheight) || 
            (py2 >= 0 && py2 < ih->currentheight) ||
            (py1 < 0 && py2 >= ih->currentheight))
          iupdrvDrawLine(dc, px1, py1, px2, py2, line_rgba, IUP_DRAW_STROKE_DOT, 1);
      }
    }

    if (node_y + node_h > 0 && node_y < ih->currentheight)
    {
      int toggle_gap = 0;
      int title_x, image_gap = 0;
      const char *fore_color = (node->fg_color) ? node->fg_color : fg_color;
      const char *back_color = (node->bg_color) ? node->bg_color : bg_color;
      const char *image = iFlatTreeGetNodeImage(ih, node, 1);

      iupImageGetInfo(image, &image_gap, NULL, NULL);
      image_gap += ih->data->icon_spacing;

      /* toggle */
      if (ih->data->show_toggle)
      {
        if (node->toggle_visible)
        {
          iFlatTreeDrawToggle(ih, dc, node, node_x, node_y, node_h, bg_color, toggle_fgcolor, toggle_bgcolor, active);
          toggle_gap = ih->data->toggle_size;
        }
        else if (ih->data->empty_toggle)
          toggle_gap = ih->data->toggle_size;
      }

      /* only the image */
      iupFlatDrawIcon(ih, dc, node_x + toggle_gap, node_y, image_gap - ih->data->icon_spacing, node_h,
                      IUP_IMGPOS_LEFT, ih->data->icon_spacing, IUP_ALIGN_ALEFT, IUP_ALIGN_ACENTER, 0, 0,
                      image, make_inactive, NULL, 0, 0, fore_color, back_color, active);

      title_x = node_x + toggle_gap + image_gap;

      if (node->selected)
      {
        char* ps_color = iupAttribGetStr(ih, "PSCOLOR");
        char* text_ps_color = iupAttribGetStr(ih, "TEXTPSCOLOR");
        if (text_ps_color)
          fore_color = text_ps_color;
        if (ps_color)
          back_color = ps_color;
      }

      /* title background */
      iupFlatDrawBox(dc, title_x, title_x + node->title_width - 1, node_y, node_y + node_h - 1, back_color, back_color, 1);

      /* only the title */
      iFlatTreeSetNodeDrawFont(ih, node, font);
      iupFlatDrawIcon(ih, dc, title_x, node_y, node->title_width, node_h,
                      IUP_IMGPOS_LEFT, ih->data->icon_spacing, IUP_ALIGN_ALEFT, IUP_ALIGN_ACENTER, 0, 0,
                      NULL, make_inactive, node->title, text_flags, 0, fore_color, back_color, active);

      /* title selection */
      if (node->selected || (ih->data->show_dragdrop && ih->data->dragover_id == node->id))
      {
        unsigned char alpha = (unsigned char)iupAttribGetInt(ih, "HLCOLORALPHA");
        if (alpha != 0)
        {
          long selcolor;
          unsigned char red, green, blue;
          char* hlcolor = iupAttribGetStr(ih, "HLCOLOR");

          if (ih->data->show_dragdrop && ih->data->dragover_id == node->id)
            alpha = (2 * alpha) / 3;

          iupStrToRGB(hlcolor, &red, &green, &blue);
          selcolor = iupDrawColor(red, green, blue, alpha);

          iupdrvDrawRectangle(dc, title_x, node_y, title_x + node->title_width - 1, node_y + node_h - 1, selcolor, IUP_DRAW_FILL, 1);
        }
      }

      /* title focus */
      if (ih->data->has_focus && ih->data->focus_id == node->id && focus_feedback)
        iupdrvDrawFocusRect(dc, title_x, node_y, title_x + node->title_width - 1, node_y + node_h - 1);

  	  if (ih->data->extratext_width)
      {
  	    int extra_x = ih->currentwidth - ih->data->extratext_width;
  	  
	      iupdrvDrawRectangle(dc, extra_x , node_y, ih->currentwidth, node_y + node_h , iupDrawStrToColor(bg_color, 0), IUP_DRAW_FILL, 1);

        if (node->extratext)
        {
          iupFlatDrawIcon(ih, dc, extra_x + 10, node_y, ih->data->extratext_width, node_h,
                          IUP_IMGPOS_LEFT, 10, IUP_ALIGN_ALEFT, IUP_ALIGN_ACENTER, 0, 0,
                          NULL, 0, node->extratext, text_flags, 0, fore_color, bg_color, active);
        }
  	  }
    }

    /* next node */

    node_y += node_h + ih->data->spacing;

    if (node->kind == IFLATTREE_BRANCH && node->state == IFLATTREE_EXPANDED && node->first_child)
      node_y = iFlatTreeDrawNodes(ih, dc, node->first_child, x, node_y, fg_color, bg_color, line_rgba, toggle_fgcolor, toggle_bgcolor, make_inactive, active,
                                  text_flags, font, focus_feedback, hide_lines);

    node = node->brother;
  }

  return node_y;
}

static int iFlatTreeDrawExpander(Ihandle *ih, IdrawCanvas* dc, iFlatTreeNode *node, long border_color, long fore_color, long back_color, const char *bgcolor, int x, int y, const char* button_plus_image, const char* button_minus_image)
{
  while (node)
  {
    if (node->kind == IFLATTREE_BRANCH && node->first_child && node->depth > 0)
    {
      int px = x + ((node->depth - 1) * ih->data->indentation) + ((ih->data->indentation - ih->data->button_size) / 2);

      if (button_plus_image && button_minus_image)
      {
        const char *button_image = (node->state == IFLATTREE_EXPANDED) ? button_minus_image : button_plus_image;
        int py = y + (node->height - ih->data->button_size) / 2;
        iupdrvDrawImage(dc, button_image, 0, bgcolor, px, py, 0, 0);
      }
      else
        iFlatTreeDrawExpanderButton(dc, node, px, y, node->height, ih->data->button_size, border_color, fore_color, back_color);
    }

    y += node->height + ih->data->spacing;

    if (node->kind == IFLATTREE_BRANCH && node->state == IFLATTREE_EXPANDED && node->first_child)
      y = iFlatTreeDrawExpander(ih, dc, node->first_child, border_color, fore_color, back_color, bgcolor, x, y, button_plus_image, button_minus_image);

    node = node->brother;
  }

  return y;
}

static int iFlatTreeRedraw_CB(Ihandle* ih)
{
  const int text_flags = IUP_ALIGN_ALEFT;
  char* fg_color = iupAttribGetStr(ih, "FGCOLOR");
  char* bg_color = iupAttribGetStr(ih, "BGCOLOR");
  long line_rgba = iupDrawStrToColor(iupAttribGetStr(ih, "LINECOLOR"), 0);
  char* toggle_bgcolor = iupAttribGetStr(ih, "TOGGLEBGCOLOR");
  char* toggle_fgcolor = iupAttribGetStr(ih, "TOGGLEFGCOLOR");
  long button_bgcolor = iupDrawStrToColor(iupAttribGetStr(ih, "BUTTONBGCOLOR"), iupDrawColor(240, 240, 240, 255));
  long button_fgcolor = iupDrawStrToColor(iupAttribGetStr(ih, "BUTTONFGCOLOR"), iupDrawColor(50, 100, 150, 255));
  long button_brdcolor = iupDrawStrToColor(iupAttribGetStr(ih, "BUTTONBRDCOLOR"), iupDrawColor(150, 150, 150, 255));
  int posx = IupGetInt(ih, "POSX");
  int posy = IupGetInt(ih, "POSY");
  char* back_image = iupAttribGet(ih, "BACKIMAGE");
  int x, y, make_inactive = 0;
  int border_width = ih->data->border_width;
  int active = IupGetInt(ih, "ACTIVE");  /* native implementation */
  int focus_feedback = iupAttribGetBoolean(ih, "FOCUSFEEDBACK");
  iFlatTreeNode *node;
  int width, height;
  char* font = IupGetAttribute(ih, "FONT");
  int hide_lines = iupAttribGetBoolean(ih, "HIDELINES");
  int hide_buttons = iupAttribGetBoolean(ih, "HIDEBUTTONS");
  char* button_plus_image = iupAttribGet(ih, "BUTTONPLUSIMAGE");
  char* button_minus_image = iupAttribGet(ih, "BUTTONMINUSIMAGE");

  IdrawCanvas* dc = iupdrvDrawCreateCanvas(ih);

  iupdrvDrawGetSize(dc, &width, &height);

  iupFlatDrawBox(dc, border_width, width - border_width - 1, border_width, height - border_width - 1, bg_color, bg_color, 1);

  if (back_image)
  {
    int backimage_zoom = iupAttribGetBoolean(ih, "BACKIMAGEZOOM");
    if (backimage_zoom)
      iupdrvDrawImage(dc, back_image, 0, bg_color, border_width, border_width, width - border_width, height - border_width);
    else
      iupdrvDrawImage(dc, back_image, 0, bg_color, border_width, border_width, -1, -1);
  }

  if (!active)
    make_inactive = 1;

  x = -posx + border_width;
  y = -posy + border_width;

  node = ih->data->root_node->first_child;
  if (node)
  {
    iFlatTreeDrawNodes(ih, dc, node, x, y, fg_color, bg_color, line_rgba, toggle_fgcolor, toggle_bgcolor, make_inactive, active,
                     text_flags, font, focus_feedback, hide_lines);

    if (!hide_buttons)
      iFlatTreeDrawExpander(ih, dc, node, button_brdcolor, button_fgcolor, button_bgcolor, bg_color, x, y, button_plus_image, button_minus_image);

    if (ih->data->extratext_width)
    {
      int extra_x = ih->currentwidth - ih->data->extratext_width;
      int px1 = extra_x + EXTRAWIDTH_SPACE;

      iupdrvDrawLine(dc, px1, 0, px1, height - 1, line_rgba, IUP_DRAW_STROKE_DOT, 1);
    }
  }

  if (border_width)
  {
    char* bordercolor = iupAttribGetStr(ih, "BORDERCOLOR");
    iupFlatDrawBorder(dc, 0, width - 1,
                          0, height - 1,
                          border_width, bordercolor, bg_color, active);
  }

  iupdrvDrawFlush(dc);

  iupdrvDrawKillCanvas(dc);

  return IUP_DEFAULT;
}

static int iFlatTreeResize_CB(Ihandle* ih, int width, int height)
{
  (void)width;
  (void)height;

  iFlatTreeUpdateScrollBar(ih);

  return IUP_DEFAULT;
}


/********************************** Rename Node ************************************************/


static void iFlatTreeGetTitlePos(Ihandle *ih, iFlatTreeNode *node, int *txt_x, int *txt_y)
{
  int node_y = iFlatTreeGetNodeY(ih, node);
  int posx = IupGetInt(ih, "POSX");
  int posy = IupGetInt(ih, "POSY");
  int border_width = ih->data->border_width;
  char *image = iFlatTreeGetNodeImage(ih, node, 1);
  int img_h = 0;
  int img_w = 0;

  iupImageGetInfo(image, &img_w, &img_h, NULL);

  *txt_x = -posx + border_width;
  *txt_y = -posy + border_width;

  *txt_x += node->depth * ih->data->indentation + img_w + ih->data->icon_spacing;
  *txt_y += node_y;

  if (ih->data->show_toggle && node->toggle_visible)
    *txt_x += ih->data->toggle_size;
}

static int iFlatTreeRenameNode(Ihandle* ih, int x)
{
  if (ih->data->show_rename && ih->data->has_focus)
  {
    iFlatTreeNode *nodeFocus = iFlatTreeGetNode(ih, ih->data->focus_id);
    if (nodeFocus)
    {
      int txt_x, txt_y;
      Ihandle* text = ih->firstchild;
      char* value;
      int extra_w;
      char* font = IupGetAttribute(ih, "FONT");

      if (iupAttribGet(ih->firstchild, "SB_VERT"))
      {
        /* ih->firstchild is vertical scrollbar */
        /* ih->firstchild->brother is horizontal scrollbar */
        text = ih->firstchild->brother->brother;
      }

      iFlatTreeSetNodeDrawFont(ih, nodeFocus, font);
      iupDrawGetTextSize(ih, "WW", 0, &extra_w, NULL, 0);

      iFlatTreeGetTitlePos(ih, nodeFocus, &txt_x, &txt_y);

      text->x = txt_x;
      text->y = txt_y;

      text->currentwidth = nodeFocus->title_width + extra_w;
      text->currentheight = nodeFocus->height;

      iupClassObjectLayoutUpdate(text);

      IupSetAttribute(text, "ALIGMENT", "ALEFT");
      IupSetStrAttribute(text, "FONT", nodeFocus->font? nodeFocus->font: font);
      IupSetAttribute(text, "VISIBLE", "YES");
      IupSetAttribute(text, "ACTIVE", "YES");
      if (!nodeFocus->title || *(nodeFocus->title) == 0)
        IupSetAttribute(text, "VALUE", "");
      else
        IupSetStrAttribute(text, "VALUE", nodeFocus->title);
      IupSetFocus(text);

      value = iupAttribGetStr(ih, "RENAMECARET");
      if (value)
        IupSetStrAttribute(text, "CARET", value);
      else
        IupSetInt(text, "CARETPOS", IupConvertXYToPos(text, x, 10));

      value = iupAttribGetStr(ih, "RENAMESELECTION");
      if (value)
        IupSetStrAttribute(text, "SELECTION", value);
    }
  }
  return 0;
}

static int iFlatTreeTextEditKEsc_CB(Ihandle* text)
{
  IupSetAttribute(text, "VISIBLE", "NO");
  IupSetAttribute(text, "ACTIVE", "NO");
  return IUP_IGNORE;  /* always ignore to avoid the defaultenter/defaultesc behavior from here */
}

static void iFlatTreeRedraw(Ihandle* ih, int calc_size, int update_scrollbar);

static int iFlatTreeTextEditKCR_CB(Ihandle* text)
{
  Ihandle* ih = text->parent;
  iFlatTreeNode *nodeFocus = iFlatTreeGetNode(ih, ih->data->focus_id);
  if (nodeFocus)
  {
    char* new_title = IupGetAttribute(text, "VALUE");

    IFnis cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB");
    if (cbRename)
    {
      if (cbRename(ih, nodeFocus->id, new_title) == IUP_IGNORE)
        return IUP_IGNORE;
    }

    if (nodeFocus->title)
      free(nodeFocus->title);

    nodeFocus->title = iupStrDup(new_title);

    IupSetAttribute(text, "VISIBLE", "NO");
    IupSetAttribute(text, "ACTIVE", "NO");

    iFlatTreeUpdateNodeSize(ih, nodeFocus);
    iFlatTreeRedraw(ih, 0, 1);
  }

  return IUP_IGNORE;  /* always ignore to avoid the defaultenter/defaultesc behavior from here */
}

static int iFlatTreeTextEditKILLFOCUS_CB(Ihandle* text)
{
  if (IupGetInt(text, "VISIBLE"))
    iFlatTreeTextEditKCR_CB(text);
  return IUP_DEFAULT;
}

static int iFlatTreeTextEditVALUECHANGED_CB(Ihandle* text)
{
  Ihandle* ih = text->parent;
  iFlatTreeNode *nodeFocus = iFlatTreeGetNode(ih, ih->data->focus_id);
  if (nodeFocus)
  {
    char *new_title = IupGetAttribute(text, "VALUE");
    char* font = IupGetAttribute(ih, "FONT");
    int new_w, extra_w;

    iFlatTreeSetNodeDrawFont(ih, nodeFocus, font);
    iupDrawGetTextSize(ih, new_title, 0, &new_w, NULL, 0);
    new_w += 2 * 5; /* add borders */

    iupDrawGetTextSize(ih, "WW", 0, &extra_w, NULL, 0);
    new_w += extra_w;

    if (new_w > text->currentwidth)
    {
      text->currentwidth = new_w;
      iupClassObjectLayoutUpdate(text);
    }
  }

  return IUP_DEFAULT;
}

static int iFlatTreeKF2_CB(Ihandle* ih)
{
  IFni cb;
  iFlatTreeNode *node = iFlatTreeGetNode(ih, ih->data->focus_id);
  if (!node)
    return IUP_IGNORE;

  cb = (IFni)IupGetCallback(ih, "SHOWRENAME_CB");
  if (cb)
  {
    if (cb(ih, ih->data->focus_id) == IUP_IGNORE)
      return IUP_DEFAULT;
  }

  iFlatTreeRenameNode(ih, 0);

  return IUP_DEFAULT;
}


/*********************************  Selection ***************************************/


static void iFlatTreeInvertSelection(Ihandle* ih)
{
  int i;
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  for (i = 0; i < count; i++)
    nodes[i]->selected = !(nodes[i]->selected);
}

static void iFlatTreeSelectAll(Ihandle* ih)
{
  int i;
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  for (i = 0; i < count; i++)
    nodes[i]->selected = 1;
}

static void iFlatTreeClearAllSelectionExcept(Ihandle* ih, iFlatTreeNode *nodeExcept)
{
  int i;
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  for (i = 0; i < count; i++)
  {
    if (nodes[i] != nodeExcept)
      nodes[i]->selected = 0;
  }
}

static void iFlatTreeSelectRange(Ihandle* ih, int id1, int id2)
{
  int i;
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);

  if (id1 < 0 || id1 >= count)
    id1 = 0;
  if (id2 < 0 || id2 >= count)
    id2 = count-1;

  if (id1 > id2)
  {
    int tmp = id1;
    id1 = id2;
    id2 = tmp;
  }

  for (i = 0; i < count; i++)
  {
    if (i >= id1 && i <= id2)
      nodes[i]->selected = 1;
  }
}

static int iFlatTreeFindSelectedNode(Ihandle* ih)
{
  int i;
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  for (i = 0; i < count; i++)
  {
    if (nodes[i]->selected)
      return i;
  }
  return -1;
}

static void iFlatTreeSelectNodeInteract(Ihandle* ih, int id, int ctrlPressed, int shftPressed)
{
  /* called only during interaction */
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  IFnii sel_cb = (IFnii)IupGetCallback(ih, "SELECTION_CB");
  int count = iupArrayCount(ih->data->node_array);

  ih->data->focus_id = id;

  if (ih->data->mark_mode == IFLATTREE_MARK_MULTIPLE)
  {
    IFnIi multi_cb = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
    IFnIi multi_un_cb = (IFnIi)IupGetCallback(ih, "MULTIUNSELECTION_CB");
    int i;

    if (shftPressed)
    {
      int start, end;
      Iarray* unsel_array = NULL;
      Iarray* sel_array = NULL;

      if (ih->data->last_selected_id == -1)
        return;

      if (multi_un_cb || sel_cb)
        unsel_array = iupArrayCreate(10, sizeof(int));

      if (multi_cb || sel_cb)
        sel_array = iupArrayCreate(10, sizeof(int));

      if (id <= ih->data->last_selected_id)
      {
        start = id;
        end = ih->data->last_selected_id;
      }
      else
      {
        start = ih->data->last_selected_id;
        end = id;
      }

      /* unselect outside interval */
      for (i = 0; i < start; i++)
      {
        if (nodes[i]->selected)
        {
          nodes[i]->selected = 0;

          /* The range is not necessarily continuous. */
          if (unsel_array)
          {
            int* un_sel_ids = (int*)iupArrayInc(unsel_array);
            int j = iupArrayCount(unsel_array);
            un_sel_ids[j - 1] = i;
          }
        }
      }

      /* select interval */
      for (i = start; i <= end; i++)
      {
        nodes[i]->selected = 1;

        /* The range is always completely included, independent if some nodes were already marked. */
        if (sel_array)
        {
          int* sel_ids = (int*)iupArrayInc(sel_array);
          int j = iupArrayCount(sel_array);
          sel_ids[j - 1] = i;
        }
      }

      /* unselect outside interval */
      for (i = end + 1; i < count; i++)
      {
        if (nodes[i]->selected)
        {
          nodes[i]->selected = 0;

          /* The range is not necessarily continuous. */
          if (unsel_array)
          {
            int* un_sel_ids = (int*)iupArrayInc(unsel_array);
            int j = iupArrayCount(unsel_array);
            un_sel_ids[j - 1] = i;
          }
        }
      }

      if (unsel_array)
      {
        int* un_sel_ids = (int*)iupArrayGetData(unsel_array);
        int un_sel_count = iupArrayCount(unsel_array);

        if (multi_un_cb)
          multi_un_cb(ih, un_sel_ids, un_sel_count);
        else
        {
          for (i = 0; i < un_sel_count; i++)
            sel_cb(ih, un_sel_ids[i], 0);
        }

        iupArrayDestroy(unsel_array);
      }

      if (sel_array)
      {
        int* sel_ids = (int*)iupArrayGetData(sel_array);
        int sel_count = iupArrayCount(sel_array);

        if (multi_cb)
          multi_cb(ih, sel_ids, sel_count);
        else
        {
          for (i = 0; i < sel_count; i++)
            sel_cb(ih, sel_ids[i], 1);
        }

        iupArrayDestroy(sel_array);
      }
    }
    else /* Shift not pressed */
    {
      int old_selected = nodes[id]->selected;

      ih->data->last_selected_id = id;

      if (ctrlPressed)
      {
        /* toggle selection */
        if (nodes[id]->selected)
          nodes[id]->selected = 0;
        else
          nodes[id]->selected = 1;
      }
      else
      {
        Iarray* unsel_array = NULL;

        if (multi_un_cb || sel_cb)
          unsel_array = iupArrayCreate(10, sizeof(int));

        /* unselect all */
        for (i = 0; i < count; i++)
        {
          if (nodes[i]->selected && i != id)
          {
            nodes[i]->selected = 0;

            /* The range is not necessarily continuous. */
            if (unsel_array)
            {
              int* un_sel_ids = (int*)iupArrayInc(unsel_array);
              int j = iupArrayCount(unsel_array);
              un_sel_ids[j - 1] = i;
            }
          }
        }

        if (unsel_array)
        {
          int* un_sel_ids = (int*)iupArrayGetData(unsel_array);
          int un_sel_count = iupArrayCount(unsel_array);

          if (multi_un_cb)
            multi_un_cb(ih, un_sel_ids, un_sel_count);
          else
          {
            for (i = 0; i < un_sel_count; i++)
              sel_cb(ih, un_sel_ids[i], 0);
          }

          iupArrayDestroy(unsel_array);
        }

        nodes[id]->selected = 1;
      }

      if (sel_cb && old_selected != nodes[id]->selected)
        sel_cb(ih, id, nodes[id]->selected);
    }
  }
  else  /* IFLATTREE_MARK_SINGLE */
  {
    int i, old_id = -1;

    /* same as iFlatTreeFindSelectedNode */
    for (i = 0; i < count; i++)
    {
      if (nodes[i]->selected)
      {
        if (i == id)
          return;

        nodes[i]->selected = 0;
        old_id = i;
        break;
      }
    }

    nodes[id]->selected = 1;

    if (sel_cb)
    {
      if (old_id != -1 && old_id != id)
        sel_cb(ih, old_id, 0);

      sel_cb(ih, id, 1);
    }
  }
}


/**************************************** Mouse *******************************************/


static int iFlatTreeCallDragDropCb(Ihandle* ih, int drag_id, int drop_id, int is_ctrl, int is_shift)
{
  IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");

  /* ignore a drop that will do nothing */
  if (is_ctrl == 0 && (drag_id - 1 == drop_id || drag_id == drop_id))
    return IUP_DEFAULT;
  if (is_ctrl != 0 && drag_id == drop_id)
    return IUP_DEFAULT;

  if (drop_id < 0)
    drop_id = -1;

  if (cbDragDrop)
    return cbDragDrop(ih, drag_id, drop_id, is_shift, is_ctrl);

  return IUP_CONTINUE; /* allow to move/copy by default if callback not defined */
}

static int iFlatTreeButton_CB(Ihandle* ih, int button, int pressed, int x, int y, char* status)
{
  IFniiiis button_cb = (IFniiiis)IupGetCallback(ih, "FLAT_BUTTON_CB");
  int id;

  ih->data->extratext_move = 0;

  if (button_cb)
  {
    if (button_cb(ih, button, pressed, x, y, status) == IUP_IGNORE)
      return IUP_DEFAULT;
  }

  id = iFlatTreeConvertXYToId(ih, x, y);

  if (button == IUP_BUTTON1 && !pressed && ih->data->show_dragdrop && ih->data->dragged_id > 0)
  {
    iFlatTreeNode *srcNode = iFlatTreeGetNode(ih, ih->data->dragged_id);
    iFlatTreeNode *dstNode = iFlatTreeGetNode(ih, id);
    iFlatTreeNode *parent;
    int equal_nodes = 0;

    if ((dstNode == srcNode) || !dstNode || !srcNode)
    {
      ih->data->dragover_id = -1;
      ih->data->dragged_id = -1;
      return IUP_DEFAULT;
    }

    if (id == -1)
    {
      if (y < 0)
        id = iFlatTreeGetFirstExpandedNodeId(ih);
      else
        id = iFlatTreeGetLastExpandedNodeId(ih);
    }

    /* If srcNode is an ancestor of dstNode then return */
    parent = dstNode;
    while (parent)
    {
      if (parent == srcNode)
      {
        if (!iupAttribGetBoolean(ih, "DROPEQUALDRAG"))
          return IUP_DEFAULT;

        equal_nodes = 1;
        break;
      }

      parent = parent->parent;
    }

    /* internal Drag&Drop */
    if (iFlatTreeCallDragDropCb(ih, ih->data->dragged_id, id, iup_iscontrol(status), iup_isshift(status)) == IUP_CONTINUE && !equal_nodes)
    {
      iFlatTreeNode *droppedNode = NULL;

      if (!iup_iscontrol(status))
        droppedNode = iFlatTreeMoveNode(ih, ih->data->dragged_id, id);
      else
        droppedNode = iFlatTreeCopyNode(ih, ih->data->dragged_id, id);

      if (!droppedNode)
        return IUP_DEFAULT;

      /* select the dropped item */
      iFlatTreeSelectNodeInteract(ih, droppedNode->id, 0, 0); /* force no ctrl and no shift for selection */

      iFlatTreeRedraw(ih, 0, 1);
    }

    ih->data->dragover_id = -1;
    ih->data->dragged_id = -1;
    return IUP_DEFAULT;
  }

  if (button == IUP_BUTTON1 && pressed && ih->data->extratext_width) 
  {
	  int extra_x = ih->currentwidth - ih->data->extratext_width;
	  if (x >= extra_x - EXTRAWIDTH_SPACE && x <= extra_x + EXTRAWIDTH_SPACE) 
    {
		  ih->data->extratext_move = x;
		  return IUP_DEFAULT;
	  }
  }

  if (id == -1)
    return IUP_DEFAULT;

  if (button == IUP_BUTTON3)
  {
    IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
    if (cbRightClick)
      cbRightClick(ih, id);
    return IUP_DEFAULT;
  }

  if (button == IUP_BUTTON1 && pressed)
  {
    iFlatTreeNode *node;
    int posx, xmin, xmax, node_x;
    int img_w = 0;
    char *image;
    int toggle_gap = 0;

    node = iFlatTreeGetNode(ih, id);
    if (!node)
      return IUP_DEFAULT;

    posx = IupGetInt(ih, "POSX");
    x += posx - ih->data->border_width;

    node_x = node->depth * ih->data->indentation;

    if (node->kind == IFLATTREE_BRANCH && node->first_child && node->depth > 0) /* has expander */
    {
      xmin = node_x - ih->data->indentation + (ih->data->indentation - ih->data->button_size) / 2;
      xmax = xmin + ih->data->button_size;

      if (x > xmin && x < xmax)  /* inside expander */
      {
        if (node->state == IFLATTREE_EXPANDED)
        {
          IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
          if (cbBranchClose && cbBranchClose(ih, node->id) == IUP_IGNORE)
            return IUP_DEFAULT;

          node->state = IFLATTREE_COLLAPSED;
        }
        else
        {
          IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
          if (cbBranchOpen && cbBranchOpen(ih, node->id) == IUP_IGNORE)
            return IUP_DEFAULT;

          node->state = IFLATTREE_EXPANDED;
        }

        iFlatTreeUpdateNodeExpanded(node);
        iFlatTreeRedraw(ih, 0, 1);  /* scrollbar update only */
        return IUP_DEFAULT;
      }
    }

    if (ih->data->show_toggle && node->toggle_visible) /* has toggle */
    {
      xmin = node_x + (ih->data->indentation - ih->data->toggle_size) / 2;
      xmax = xmin + ih->data->toggle_size;

      if (x > xmin && x < xmax)  /* inside toggle */
      {
        IFnii tv_cb = (IFnii)IupGetCallback(ih, "TOGGLEVALUE_CB");
        int check;

        if (node->toggle_value > 0)  /* was ON */
        {
          if (ih->data->show_toggle == 2)
            check = -1;
          else
            check = 0;
        }
        else if (node->toggle_value == -1)
          check = 0;
        else  /* was OFF */
          check = 1;

        if (tv_cb)
        {
          if (tv_cb(ih, id, check) == IUP_IGNORE)
            return IUP_DEFAULT;
        }

        node->toggle_value = check;

        /* same as IupTree, it does not triggers a selection callback */
        if (iupAttribGetBoolean(ih, "MARKWHENTOGGLE"))
          IupSetAttributeId(ih, "MARKED", node->id, node->toggle_value > 0 ? "Yes" : "No");

        iFlatTreeRedraw(ih, 0, 0);
        return IUP_DEFAULT;
      }

      toggle_gap = ih->data->toggle_size;
    }

    if (ih->data->show_toggle && !node->toggle_visible && ih->data->empty_toggle)
      toggle_gap = ih->data->toggle_size;

    image = iFlatTreeGetNodeImage(ih, node, 1);
    iupImageGetInfo(image, &img_w, NULL, NULL);

    xmin = node_x + toggle_gap;
    xmax = xmin + img_w + ih->data->icon_spacing + node->title_width;

    if (x > xmin && x < xmax)  /* inside image+title */
    {
      if (iup_isdouble(status))
      {
        if (node->kind == IFLATTREE_LEAF)
        {
          IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
          if (cbExecuteLeaf)
            cbExecuteLeaf(ih, id);
        }
        else  /* BRANCH */
        {
          IFni cbExecuteBranch = (IFni)IupGetCallback(ih, "EXECUTEBRANCH_CB");
          if (cbExecuteBranch)
            cbExecuteBranch(ih, node->id);

          if (node->state == IFLATTREE_EXPANDED)
          {
            IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
            if (cbBranchClose && cbBranchClose(ih, node->id) == IUP_IGNORE)
              return IUP_DEFAULT;

            node->state = IFLATTREE_COLLAPSED;
          }
          else
          {
            IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
            if (cbBranchOpen && cbBranchOpen(ih, node->id) == IUP_IGNORE)
              return IUP_DEFAULT;

            node->state = IFLATTREE_EXPANDED;
          }

          iFlatTreeUpdateNodeExpanded(node);
          iFlatTreeRedraw(ih, 0, 1);  /* scrollbar update only */
        }

        return IUP_DEFAULT;
      }
      else
      {
        if (ih->data->show_rename && id == ih->data->focus_id && x > xmin + img_w + ih->data->icon_spacing)
        {
          clock_t current_clock = clock();
          clock_t diff_clock = current_clock - ih->data->last_clock;
          if (diff_clock < 1000)
          {
            IFni cb = (IFni)IupGetCallback(ih, "SHOWRENAME_CB");
            if (cb)
            {
              if (cb(ih, id) == IUP_IGNORE)
                return IUP_DEFAULT;
            }

            return iFlatTreeRenameNode(ih, x - (xmin + img_w + ih->data->icon_spacing));
          }

          ih->data->last_clock = current_clock;
        }

        /* single click in the image+title area */

        ih->data->dragged_id = id;

        iFlatTreeSelectNodeInteract(ih, id, iup_iscontrol(status), iup_isshift(status));

        iFlatTreeRedraw(ih, 0, 0);
      }
    }
  }

  return IUP_DEFAULT;
}

static int iFlatTreeMotion_CB(Ihandle* ih, int x, int y, char* status)
{
  IFniis motion_cb = (IFniis)IupGetCallback(ih, "FLAT_MOTION_CB");
  int id;

  iupFlatScrollBarMotionUpdate(ih, x, y);

  if (motion_cb)
  {
    if (motion_cb(ih, x, y, status) == IUP_IGNORE)
      return IUP_DEFAULT;
  }

  if (ih->data->extratext_width)
  {
    int extra_x = ih->currentwidth - ih->data->extratext_width;
    if (x >= extra_x - EXTRAWIDTH_SPACE && x <= extra_x + EXTRAWIDTH_SPACE)
      IupSetAttribute(ih, "CURSOR", "SPLITTER_VERT");
    else
      IupSetAttribute(ih, "CURSOR", "ARROW");
  }

  if (iup_isbutton1(status) && ih->data->extratext_width && ih->data->extratext_move)
  {
    ih->data->extratext_width = ih->currentwidth - x;
    IupRedraw(ih, 0);
    return IUP_DEFAULT;
  }

  id = iFlatTreeConvertXYToId(ih, x, y);
  if (id < 0)
  {
    iupFlatItemResetTip(ih);
    return IUP_DEFAULT;
  }
  else
  {
    iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
    char* item_tip = nodes[id]->tip;
    if (item_tip)
      iupFlatItemSetTip(ih, item_tip);
    else
      iupFlatItemResetTip(ih);
  }

  if (!iup_isbutton1(status))
    return IUP_IGNORE;

  /* button1 is pressed => dragging */

  if (ih->data->mark_mode == IFLATTREE_MARK_MULTIPLE && !ih->data->show_dragdrop)
  {
    if (ih->data->last_selected_id == ih->data->dragged_id)
    {
      /* multiple selection while dragging when SHOWDRAGDROP=NO */
      iFlatTreeSelectNodeInteract(ih, id, 0, 1);
    }
  }

  if (y < 0 || y > ih->currentheight)
  {
    /* scroll if dragging out of canvas */
    int node_h;
    int dy = IupGetInt(ih, "DY");
    int node_y = iFlatTreeConvertIdToY(ih, id, &node_h);
    int posy = (y < 0) ? node_y : (node_y + node_h) - dy;
    IupSetInt(ih, "POSY", posy);
  }

  if (ih->data->show_dragdrop && ih->data->dragged_id >= 0)
    ih->data->dragover_id = id;

  IupRedraw(ih, 0);

  return IUP_DEFAULT;
}

static int iFlatTreeLeaveWindow_CB(Ihandle* ih)
{
  IFn cb = (IFn)IupGetCallback(ih, "FLAT_LEAVEWINDOW_CB");
  if (cb)
  {
    if (cb(ih) == IUP_IGNORE)
      return IUP_DEFAULT;
  }

  iupFlatItemResetTip(ih);

  return IUP_DEFAULT;
}


/*********************************  Focus ************************************/


static int iFlatTreeFocusPageDown(Ihandle *ih)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int dy = IupGetInt(ih, "DY");
  int i;
  int total_h = nodes[ih->data->focus_id]->height + ih->data->spacing;

  if (ih->data->focus_id == count - 1)
    return ih->data->focus_id;

  for (i = ih->data->focus_id + 1; i < count-1; i++)
  {
    if (!nodes[i]->expanded)
      continue;

    total_h += nodes[i]->height + ih->data->spacing;
    if (total_h > dy)
      break;
  }

  return i;
}

static int iFlatTreeFocusPageUp(Ihandle *ih)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int dy = IupGetInt(ih, "DY");
  int i;
  int total_h = 0;

  if (ih->data->focus_id == 0)
    return ih->data->focus_id;

  for (i = ih->data->focus_id - 1; i > 0; i--)
  {
    if (!nodes[i]->expanded)
      continue;

    total_h += (nodes[i]->height + ih->data->spacing);

    if (total_h + nodes[i]->height > dy)
      break;
  }

  return i;
}

static int iFlatTreeFocus_CB(Ihandle* ih, int focus)
{
  IFni cb = (IFni)IupGetCallback(ih, "FLAT_FOCUS_CB");
  if (cb)
  {
    if (cb(ih, focus) == IUP_IGNORE)
      return IUP_DEFAULT;
  }

  ih->data->has_focus = focus;

  IupRedraw(ih, 0);

  return IUP_DEFAULT;
}

static int iFlatTreeScroll_CB(Ihandle* ih, int action, float posx, float posy)
{
  Ihandle* text = ih->firstchild;

  if (iupAttribGet(ih->firstchild, "SB_VERT"))
  {
    /* ih->firstchild is vertical scrollbar */
    /* ih->firstchild->brother is horizontal scrollbar */
    text = ih->firstchild->brother->brother;
  }

  if (IupGetInt(text, "VISIBLE"))
    iFlatTreeTextEditKCR_CB(text);

  iupdrvRedrawNow(ih);  /* so FLATSCROLLBAR can also work */

  (void)action;
  (void)posx;
  (void)posy;
  return IUP_DEFAULT;
}

static void iFlatTreeScrollFocusVisible(Ihandle* ih, int direction)
{
  /* make sure focus node is visible */
  int posy, node_y, node_height;
  int dy = IupGetInt(ih, "DY");
  int ymax = IupGetInt(ih, "YMAX");

  if (dy >= ymax)
  {
    IupRedraw(ih, 0);
    return;
  }

  node_y = iFlatTreeConvertIdToY(ih, ih->data->focus_id, &node_height);
  posy = IupGetInt(ih, "POSY");

  if (node_y >= posy && (node_y + node_height) < (posy + dy))
  {
    /* already visible, does nothing */
  }
  else
  {
    if (direction == IFLATTREE_DOWN)
      posy = node_y + node_height - dy;
    else  /* IFLATTREE_UP */
      posy = node_y;

    IupSetInt(ih, "POSY", posy);
  }

  IupRedraw(ih, 0);
}

static int iFlatTreeKCr_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
    {
      iFlatTreeNode *node = iFlatTreeGetNode(ih, ih->data->focus_id);

      if (node->kind == IFLATTREE_BRANCH)
      {
        IFni cbExecuteBranch = (IFni)IupGetCallback(ih, "EXECUTEBRANCH_CB");
        if (cbExecuteBranch)
          cbExecuteBranch(ih, node->id);

        if (node->state == IFLATTREE_EXPANDED)
        {
          IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
          if (cbBranchClose && cbBranchClose(ih, node->id) == IUP_IGNORE)
            return IUP_DEFAULT;

          node->state = IFLATTREE_COLLAPSED;
        }
        else
        {
          IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
          if (cbBranchOpen && cbBranchOpen(ih, node->id) == IUP_IGNORE)
            return IUP_DEFAULT;

          node->state = IFLATTREE_EXPANDED;
        }

        iFlatTreeUpdateNodeExpanded(node);
        iFlatTreeRedraw(ih, 0, 1);  /* scrollbar update only */
      }
      else
      {
        IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
        if (cbExecuteLeaf)
          cbExecuteLeaf(ih, ih->data->focus_id);
      }
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKUp_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id > 0 && ih->data->focus_id < count)  /* focus can decrease 1 */
    {
      int ctrltPressed = IupGetInt(NULL, "CONTROLKEY");
      int previousId = iFlatTreeGetPreviousExpandedNodeId(ih, ih->data->focus_id);

      if (ctrltPressed)
        ih->data->focus_id = previousId;
      else
      {
        int shftPressed = IupGetInt(NULL, "SHIFTKEY");
        iFlatTreeSelectNodeInteract(ih, previousId, 0, shftPressed);
      }

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_UP);
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKDown_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count-1)  /* focus can increase 1 */
    {
      int ctrltPressed = IupGetInt(NULL, "CONTROLKEY");
      int nextId = iFlatTreeGetNextExpandedNodeId(ih, ih->data->focus_id);

      if (ctrltPressed)
        ih->data->focus_id = nextId;
      else
      {
        int shftPressed = IupGetInt(NULL, "SHIFTKEY");
        iFlatTreeSelectNodeInteract(ih, nextId, 0, shftPressed);
      }

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_DOWN);
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKcSpace_CB(Ihandle* ih)
{
  IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
  iFlatTreeNode *node = iFlatTreeGetNode(ih, ih->data->focus_id);
  if (!node)
    return IUP_IGNORE;

  if (node->selected)
  {
    /* unselect */
    node->selected = 0;

    if (cbSelec)
      cbSelec(ih, node->id, 0);
  }
  else
  {
    if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
    {
      int old_id = iFlatTreeFindSelectedNode(ih);
      iFlatTreeNode *old_node = iFlatTreeGetNode(ih, old_id);

      if (old_node)
        old_node->selected = 0;

      if (cbSelec && old_id >= 0)
        cbSelec(ih, old_id, 0);
    }

    /* select */
    node->selected = 1;

    if (cbSelec)
      cbSelec(ih, node->id, 1);
  }

  IupRedraw(ih, 0);

  return IUP_DEFAULT;
}

static int iFlatTreeKHome_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
    {
      int shftPressed = IupGetInt(NULL, "SHIFTKEY");
      int id = iFlatTreeConvertPosToId(ih, 0);

      iFlatTreeSelectNodeInteract(ih, id, 0, shftPressed);

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_UP);
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKEnd_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
    {
      int shftPressed = IupGetInt(NULL, "SHIFTKEY");
      int id = iFlatTreeGetLastExpandedNodeId(ih);

      iFlatTreeSelectNodeInteract(ih, id, 0, shftPressed);

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_DOWN);
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKPgUp_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
    {
      int shftPressed = IupGetInt(NULL, "SHIFTKEY");
      int id = iFlatTreeFocusPageUp(ih);

      iFlatTreeSelectNodeInteract(ih, id, 0, shftPressed);

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_UP);
    }
  }
  return IUP_DEFAULT;
}

static int iFlatTreeKPgDn_CB(Ihandle* ih)
{
  if (ih->data->has_focus)
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
    {
      int shftPressed = IupGetInt(NULL, "SHIFTKEY");
      int id = iFlatTreeFocusPageDown(ih);

      iFlatTreeSelectNodeInteract(ih, id, 0, shftPressed);

      iFlatTreeScrollFocusVisible(ih, IFLATTREE_DOWN);
    }
  }
  return IUP_DEFAULT;
}


/*********************************  Drag & Drop  ********************************/


static void iFlatTreeDragDropCopyNode(Ihandle *ih_source, Ihandle *ih, iFlatTreeNode *srcNode, iFlatTreeNode *dstNode, int isControl)
{
  iFlatTreeNode *newNode;
  int count = iFlatTreeGetChildCount(srcNode) + 1;

  if (isControl)
    newNode = iFlatTreeCloneNode(srcNode);    /* Copy */
  else
  {
    iFlatTreeUnlinkNodeFromParent(srcNode);  /* Move */
    newNode = srcNode;
  }

  if (dstNode->kind == IFLATTREE_BRANCH && dstNode->state == IFLATTREE_EXPANDED)
  {
    /* copy as first child of expanded branch */
    newNode->parent = dstNode;
    newNode->brother = dstNode->first_child;
    dstNode->first_child = newNode;
  }
  else
  {
    newNode->parent = dstNode->parent;
    newNode->brother = dstNode->brother;
    dstNode->brother = newNode;
  }

  iFlatTreeRebuildArray(ih, +count);

  if (isControl)
    iFlatTreeUpdateNodeSize(ih, newNode);

  iFlatTreeUpdateNodeExpanded(newNode);
  iFlatTreeRedraw(ih, 0, 1);

  if (!isControl)
  {
    iFlatTreeRebuildArray(ih_source, -count);
    iFlatTreeRedraw(ih_source, 0, 1);
  }
}

static int iFlatTreeDropData_CB(Ihandle *ih, char* type, void* data, int len, int x, int y)
{
  iFlatTreeNode *itemDst, *itemSrc;
  int dst_id, src_id;
  int is_ctrl = 0;
  char key[5];

  /* Data is not the pointer, it contains the pointer */
  Ihandle* ih_source;
  memcpy((void*)&ih_source, data, len);

  /*TODO support IupTree??? */
  if (!IupClassMatch(ih_source, "flattree"))
    return IUP_DEFAULT;

  /* A copy operation is enabled with the CTRL key pressed, or else a move operation will occur.
     A move operation will be possible only if the attribute DRAGSOURCEMOVE is Yes.
     When no key is pressed the default operation is copy when DRAGSOURCEMOVE=No and move when DRAGSOURCEMOVE=Yes. */
  iupdrvGetKeyState(key);
  if (key[1] == 'C')
    is_ctrl = 1;

  /* Here copy/move of multiple selection is not allowed,
     only a single node and its children. */

  src_id = iupAttribGetInt(ih_source, "_IUP_TREE_SOURCEID");
  dst_id = iFlatTreeConvertXYToId(ih, x, y);

  itemSrc = iFlatTreeGetNode(ih_source, src_id);
  if (!itemSrc)
    return IUP_DEFAULT;

  itemDst = iFlatTreeGetNode(ih, dst_id);
  if (!itemDst)
    return IUP_DEFAULT;

  /* Copy the node and its children to the new position */
  iFlatTreeDragDropCopyNode(ih_source, ih, itemSrc, itemDst, is_ctrl);

  (void)type;
  return IUP_DEFAULT;
}

static int iFlatTreeDragData_CB(Ihandle *ih, char* type, void *data, int len)
{
  int id = iupAttribGetInt(ih, "_IUP_TREE_SOURCEID");
  if (id < 1)
    return IUP_DEFAULT;

  if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
  {
    /* Single selection */
    IupSetAttributeId(ih, "MARKED", id, "YES");
  }

  /* Copy source handle */
  memcpy(data, (void*)&ih, len);

  (void)type;
  return IUP_DEFAULT;
}

static int iFlatTreeDragDataSize_CB(Ihandle* ih, char* type)
{
  (void)ih;
  (void)type;
  return sizeof(Ihandle*);
}

static int iFlatTreeDragEnd_CB(Ihandle *ih, int del)
{
  iupAttribSetInt(ih, "_IUP_TREE_SOURCEID", -1);
  (void)del;
  return IUP_DEFAULT;
}

static int iFlatTreeDragBegin_CB(Ihandle* ih, int x, int y)
{
  int id = iFlatTreeConvertXYToId(ih, x, y);
  iupAttribSetInt(ih, "_IUP_TREE_SOURCEID", id);  /* works for IupTree and IupFlatTree */
  return IUP_DEFAULT;
}


/*********************************  Attributes  ********************************/

static void iFlatTreeRedraw(Ihandle* ih, int calc_size, int update_scrollbar)
{
  if (ih->data->auto_redraw)
  {
    if (calc_size)
      iFlatTreeUpdateNodeSizeAll(ih);

    if (update_scrollbar)
      iFlatTreeUpdateScrollBar(ih);

    IupRedraw(ih, 0);
  }
}

static char* iFlatTreeGetAutoRedrawAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->auto_redraw);
}

static int iFlatTreeSetAutoRedrawAttrib(Ihandle* ih, const char* value)
{
  if (iupStrBoolean(value))
  {
    ih->data->auto_redraw = 1;

    iFlatTreeRedraw(ih, 1, 1);
  }
  else
    ih->data->auto_redraw = 0;

  return 0;
}

static char* iFlatTreeGetEmptyToggleAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->empty_toggle);
}

static int iFlatTreeSetEmptyToggleAttrib(Ihandle* ih, const char* value)
{
  ih->data->empty_toggle = iupStrBoolean(value);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetAddExpandedAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->add_expanded);
}

static int iFlatTreeSetAddExpandedAttrib(Ihandle* ih, const char* value)
{
  if (iupStrBoolean(value))
    ih->data->add_expanded = 1;
  else
    ih->data->add_expanded = 0;

  return 0;
}

static char* iFlatTreeGetIndentationAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->indentation);
}

static int iFlatTreeSetIndentationAttrib(Ihandle* ih, const char* value)
{
  if (!value)
  {
    int high_dpi = iupIsHighDpi();
    ih->data->indentation = high_dpi ? 24 : 16;
  }
  else
    iupStrToInt(value, &ih->data->indentation);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetShowToggleAttrib(Ihandle* ih)
{
  if (ih->data->show_toggle)
  {
    if (ih->data->show_toggle == 2)
      return "3STATE";
    else
      return "YES";
  }
  else
    return "NO";
}

static int iFlatTreeSetShowToggleAttrib(Ihandle* ih, const char* value)
{
  if (iupStrEqualNoCase(value, "3STATE"))
    ih->data->show_toggle = 2;
  else if (iupStrBoolean(value))
    ih->data->show_toggle = 1;
  else
    ih->data->show_toggle = 0;

  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static int iFlatTreeSetSpacingAttrib(Ihandle* ih, const char* value)
{
  iupStrToInt(value, &ih->data->spacing);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetSpacingAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->spacing);
}

static int iFlatTreeSetToggleSizeAttrib(Ihandle* ih, const char* value)
{
  if (!value)
  {
    int high_dpi = iupIsHighDpi();
    ih->data->toggle_size = high_dpi ? 24 : 16;
  }
  else
    iupStrToInt(value, &ih->data->toggle_size);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetToggleSizeAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->toggle_size);
}

static int iFlatTreeSetButtonSizeAttrib(Ihandle* ih, const char* value)
{
  iupStrToInt(value, &ih->data->button_size);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetButtonSizeAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->button_size);
}

static char* iFlatTreeGetHasFocusAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->has_focus);
}

static char* iFlatTreeGetStateAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  if (node->kind == IFLATTREE_LEAF)
    return NULL;

  if (node->state == IFLATTREE_EXPANDED)
    return "EXPANDED";
  else
    return "COLLAPSED";
}

static int iFlatTreeSetStateAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->kind == IFLATTREE_LEAF)
    return 0;

  if (iupStrEqualNoCase(value, "EXPANDED"))
    node->state = IFLATTREE_EXPANDED;
  else /* "HORIZONTAL" */
    node->state = IFLATTREE_COLLAPSED;

  iFlatTreeUpdateNodeExpanded(node);
  iFlatTreeRedraw(ih, 0, 1);  /* scrollbar update only */
  return 0;
}

static char* iFlatTreeGetKindAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  if (node->kind == IFLATTREE_BRANCH)
    return "BRANCH";
  else
    return "LEAF";
}

static char* iFlatTreeGetParentAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  if (node->parent->id == -1)
    return NULL;

  return iupStrReturnInt(node->parent->id);
}

static char* iFlatTreeGetNextAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node || !node->brother)
    return NULL;

  return iupStrReturnInt(node->brother->id);
}

static char* iFlatTreeGetPreviousAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  iFlatTreeNode *brother;
  if (!node)
    return NULL;

  brother = node->parent->first_child;

  if (brother == node)
    return NULL;

  while (brother->brother != node)
    brother = brother->brother;

  return iupStrReturnInt(brother->id);
}

static char* iFlatTreeGetLastAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *nodeLast = NULL;
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  nodeLast = node;
  while (nodeLast->brother)
    nodeLast = nodeLast->brother;

  return iupStrReturnInt(nodeLast->id);
}

static char* iFlatTreeGetFirstAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return iupStrReturnInt(node->parent->first_child->id);
}

static char* iFlatTreeGetTitleAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;
  return iupStrReturnStr(node->title);
}

static int iFlatTreeSetTitleAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  node->title = iupStrDup(value);

  iFlatTreeUpdateNodeSize(ih, node);
  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetTitleFontAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->font;
}

static int iFlatTreeSetTitleFontAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->font)
    free(node->font);
  node->font = iupStrDup(value);

  iFlatTreeUpdateNodeSize(ih, node);
  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetTitleFontStyleAttrib(Ihandle* ih, int id)
{
  int size = 0;
  int is_bold = 0,
    is_italic = 0,
    is_underline = 0,
    is_strikeout = 0;
  char typeface[1024];

  char* font = IupGetAttributeId(ih, "TITLEFONT", id);
  if (!font)
    font = IupGetAttribute(ih, "FONT");

  if (!iupGetFontInfo(font, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
    return NULL;

  return iupStrReturnStrf("%s%s%s%s", is_bold ? "Bold " : "", is_italic ? "Italic " : "", is_underline ? "Underline " : "", is_strikeout ? "Strikeout " : "");
}

static int iFlatTreeSetTitleFontSizeAttrib(Ihandle* ih, int id, const char* value)
{
  int size = 0;
  int is_bold = 0,
    is_italic = 0,
    is_underline = 0,
    is_strikeout = 0;
  char typeface[1024];
  char* font;

  if (!value)
    return 0;

  font = IupGetAttributeId(ih, "TITLEFONT", id);
  if (!font)
    font = IupGetAttribute(ih, "FONT");

  if (!iupGetFontInfo(font, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
    return 0;

  IupSetfAttributeId(ih, "TITLEFONT", id, "%s, %s%s%s%s %s", typeface, is_bold ? "Bold " : "", is_italic ? "Italic " : "", is_underline ? "Underline " : "", is_strikeout ? "Strikeout " : "", value);

  return 0;
}

static char* iFlatTreeGetTitleFontSizeAttrib(Ihandle* ih, int id)
{
  int size = 0;
  int is_bold = 0,
    is_italic = 0,
    is_underline = 0,
    is_strikeout = 0;
  char typeface[1024];

  char* font = IupGetAttributeId(ih, "TITLEFONT", id);
  if (!font)
    font = IupGetAttribute(ih, "FONT");

  if (!iupGetFontInfo(font, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
    return NULL;

  return iupStrReturnInt(size);
}

static int iFlatTreeSetTitleFontStyleAttrib(Ihandle* ih, int id, const char* value)
{
  int size = 0;
  int is_bold = 0,
    is_italic = 0,
    is_underline = 0,
    is_strikeout = 0;
  char typeface[1024];
  char* font;

  if (!value)
    return 0;

  font = IupGetAttributeId(ih, "TITLEFONT", id);
  if (!font)
    font = IupGetAttribute(ih, "FONT");

  if (!iupGetFontInfo(font, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
    return 0;

  IupSetfAttributeId(ih, "TITLEFONT", id, "%s, %s %d", typeface, value, size);

  return 0;
}

static char* iFlatTreeGetToggleValueAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node;

  if (!ih->data->show_toggle)
    return NULL;

  node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  if (!node->toggle_visible)
    return NULL;

  return iupStrReturnChecked(node->toggle_value);
}

static int iFlatTreeSetToggleValueAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node;

  if (!ih->data->show_toggle)
    return 0;

  node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (!node->toggle_visible)
    return 0;

  if (ih->data->show_toggle == 2 && iupStrEqualNoCase(value, "NOTDEF"))
    node->toggle_value = -1;  /* indeterminate, inconsistent */
  else if (iupStrEqualNoCase(value, "ON"))
    node->toggle_value = 1;
  else
    node->toggle_value = 0;

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static char* iFlatTreeGetToggleVisibleAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node;

  if (!ih->data->show_toggle)
    return NULL;

  node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return iupStrReturnBoolean(node->toggle_visible);
}

static int iFlatTreeSetToggleVisibleAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node;

  if (!ih->data->show_toggle)
    return 0;

  node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  node->toggle_visible = iupStrBoolean(value);

  iFlatTreeUpdateNodeSize(ih, node);
  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetUserDataAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = (iFlatTreeNode *)iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->userdata;
}

static int iFlatTreeSetUserDataAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = (iFlatTreeNode *)iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  node->userdata = (void*)value;
  return 0;
}

static int iFlatTreeSetRenameAttrib(Ihandle* ih, const char* value)
{
  iFlatTreeRenameNode(ih, 0);
  (void)value;
  return 0;
}

static char* iFlatTreeGetLastAddNodeAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->last_add_id);
}

static int iFlatTreeSetAddLeafAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeAddNode(ih, id, IFLATTREE_LEAF, value);

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static int iFlatTreeSetAddBranchAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeAddNode(ih, id, IFLATTREE_BRANCH, value);

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static int iFlatTreeSetInsertLeafAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeInsertNode(ih, id, IFLATTREE_LEAF, value);

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static int iFlatTreeSetInsertBranchAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeInsertNode(ih, id, IFLATTREE_BRANCH, value);

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static void iFlatTreeRemoveMarkedNodes(Ihandle *ih, iFlatTreeNode *node, IFns noderemoved_cb)
{
  while (node)
  {
    if (node->selected)
    {
      iFlatTreeNode *brother = node->brother;
      iFlatTreeRemoveNode(ih, node, noderemoved_cb);
      node = brother;
    }
    else if (node->kind == IFLATTREE_BRANCH)
    {
      iFlatTreeRemoveMarkedNodes(ih, node->first_child, noderemoved_cb);
      node = node->brother;
    }
    else
      node = node->brother;
  }
}

static int iFlatTreeSetDelNodeAttrib(Ihandle* ih, int id, const char* value)
{
  IFns noderemoved_cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB");
  int update = 0;

  if (iupStrEqualNoCase(value, "ALL"))
  {
    iFlatTreeNode *child = ih->data->root_node->first_child;
    while (child)
    {
      iFlatTreeNode *brother = child->brother;
      iFlatTreeRemoveNode(ih, child, noderemoved_cb);
      child = brother;
    }
    ih->data->root_node->first_child = NULL;
    iFlatTreeRebuildArray(ih, 0);
    update = 1;
  }

  if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the reference one */
  {
    iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
    if (node)
    {
      int count = iFlatTreeGetChildCount(node) + 1;
      iFlatTreeUnlinkNodeFromParent(node);
      iFlatTreeRemoveNode(ih, node, noderemoved_cb);
      iFlatTreeRebuildArray(ih, -count);
      update = 1;
    }
  }
  else if (iupStrEqualNoCase(value, "CHILDREN"))  /* children of the reference node */
  {
    iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
    if (node)
    {
      int count = 0;
      iFlatTreeNode *child = node->first_child;
      while (child)
      {
        iFlatTreeNode *brother = child->brother;
        count += iFlatTreeGetChildCount(child) + 1;
        iFlatTreeRemoveNode(ih, child, noderemoved_cb);
        child = brother;
      }
      node->first_child = NULL;
      iFlatTreeRebuildArray(ih, -count);
      update = 1;
    }
  }
  else if (iupStrEqualNoCase(value, "MARKED"))
  {
    iFlatTreeRemoveMarkedNodes(ih, ih->data->root_node->first_child, noderemoved_cb);
    iFlatTreeRebuildArray(ih, 0);
    update = 1;
  }

  if (update)
    iFlatTreeRedraw(ih, 0, 1);

  return 0;
}

static int iFlatTreeSetExpandAllAttrib(Ihandle* ih, const char* value)
{
  int count = iupArrayCount(ih->data->node_array);
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int i, state = iupStrBoolean(value)? IFLATTREE_EXPANDED: IFLATTREE_COLLAPSED;

  for (i = 0; i < count; i++)
  {
    if (nodes[i]->kind == IFLATTREE_LEAF)
      continue;

    nodes[i]->state = state;
    nodes[i]->expanded = 1;
  }

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static int iFlatTreeSetMoveNodeAttrib(Ihandle* ih, int id, const char* value)
{
  int dstId = IUP_INVALID_ID;
  if (iupStrToInt(value, &dstId))
  {
    iFlatTreeMoveNode(ih, id, dstId);

    iFlatTreeRedraw(ih, 0, 1);
  }

  return 0;
}

static int iFlatTreeSetCopyNodeAttrib(Ihandle* ih, int id, const char* value)
{
  int dstId = IUP_INVALID_ID;
  if (iupStrToInt(value, &dstId))
  {
    iFlatTreeCopyNode(ih, id, dstId);

    iFlatTreeRedraw(ih, 0, 1);
  }

  return 0;
}

static int iFlatTreeSetValueAttrib(Ihandle* ih, const char* value)
{
  int old_focus_id = ih->data->focus_id;
  int new_focus_id = -1;

  if (iupStrEqualNoCase(value, "ROOT") || iupStrEqualNoCase(value, "FIRST"))
     new_focus_id = 0;
  else if (iupStrEqualNoCase(value, "LAST"))
     new_focus_id = iFlatTreeGetLastExpandedNodeId(ih);
  else if (iupStrEqualNoCase(value, "PGUP"))
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
       new_focus_id = iFlatTreeFocusPageUp(ih);
  }
  else if (iupStrEqualNoCase(value, "PGDN"))
  {
    int count = iupArrayCount(ih->data->node_array);
    if (ih->data->focus_id >= 0 && ih->data->focus_id < count)
       new_focus_id = iFlatTreeFocusPageDown(ih);
  }
  else if (iupStrEqualNoCase(value, "NEXT"))
     new_focus_id = iFlatTreeGetNextExpandedNodeId(ih, ih->data->focus_id);
  else if (iupStrEqualNoCase(value, "PREVIOUS"))
     new_focus_id = iFlatTreeGetPreviousExpandedNodeId(ih, ih->data->focus_id);
  else if (iupStrEqualNoCase(value, "CLEAR"))
     new_focus_id = -1;
  else
  {
    int id = IUP_INVALID_ID;
    if (iupStrToInt(value, &id))
    {
      int count = iupArrayCount(ih->data->node_array);
      if (id >= 0 && id < count)
         new_focus_id = id;
    }
  }

  if (new_focus_id != -1 && new_focus_id != old_focus_id)
  {
    int direction = (old_focus_id < new_focus_id) ? IFLATTREE_DOWN : IFLATTREE_UP;
    iFlatTreeNode *node = iFlatTreeGetNode(ih, new_focus_id);

    if (!node || !node->expanded)
      return 0;

    ih->data->focus_id = new_focus_id;

    if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
    {
      node->selected = 1;
      iFlatTreeClearAllSelectionExcept(ih, node);
    }

    iFlatTreeScrollFocusVisible(ih, direction);
  }

  return 0;
}

static char* iFlatTreeGetValueAttrib(Ihandle* ih)
{
  int count = iupArrayCount(ih->data->node_array);
  if (ih->data->focus_id < 0 || ih->data->focus_id >= count)
  {
    if (count == 0)
      return "-1";
    else
      return "0";
  }
  else
    return iupStrReturnInt(ih->data->focus_id);
}

static int iFlatTreeSetMarkAttrib(Ihandle* ih, const char* value)
{
  if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
    return 0;

  if (iupStrEqualNoCase(value, "BLOCK"))
    iFlatTreeSelectRange(ih, ih->data->mark_start_id, ih->data->focus_id);
  else if (iupStrEqualNoCase(value, "CLEARALL"))
    iFlatTreeClearAllSelectionExcept(ih, NULL);
  else if (iupStrEqualNoCase(value, "MARKALL"))
    iFlatTreeSelectAll(ih);
  else if (iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */
    iFlatTreeInvertSelection(ih);
  else if (iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */
  {
    iFlatTreeNode *node = iFlatTreeGetNodeFromString(ih, &value[strlen("INVERT")]);
    if (!node)
      return 0;

    node->selected = !(node->selected); /* toggle */
  }
  else
  {
    int id1, id2;

    if (iupStrToIntInt(value, &id1, &id2, '-') != 2)
      return 0;

    iFlatTreeSelectRange(ih, id1, id2);
  }

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static int iFlatTreeSetMarkStartAttrib(Ihandle* ih, const char* value)
{
  int id;
  if (iupStrToInt(value, &id))
  {
    int count = iupArrayCount(ih->data->node_array);

    if (id >= 0 && id < count)
      ih->data->mark_start_id = id;
  }

  return 0;
}

static char* iFlatTreeGetMarkStartAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->mark_start_id);
}

static char* iFlatTreeGetMarkedAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return iupStrReturnBoolean(node->selected);
}

static int iFlatTreeSetMarkedAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  node->selected = iupStrBoolean(value);

  if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE && node->selected)
    iFlatTreeClearAllSelectionExcept(ih, node);

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static char* iFlatTreeGetMarkedNodesAttrib(Ihandle* ih)
{
  iFlatTreeNode **nodes = iupArrayGetData(ih->data->node_array);
  int count = iupArrayCount(ih->data->node_array);
  char* str = iupStrGetMemory(count + 1);
  int i;

  for (i = 0; i < count; i++)
  {
    if (nodes[i]->selected)
      str[i] = '+';
    else
      str[i] = '-';
  }

  str[count] = 0;
  return str;
}

static int iFlatTreeSetMarkedNodesAttrib(Ihandle* ih, const char* value)
{
  int count, i, len;
  iFlatTreeNode **nodes;

  if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE || !value)
    return 0;

  count = iupArrayCount(ih->data->node_array);
  nodes = iupArrayGetData(ih->data->node_array);

  len = (int)strlen(value);
  if (len < count)
    count = len;

  for (i = 0; i < count; i++)
  {
    if (value[i] == '+')
      nodes[i]->selected = 1;
    else
      nodes[i]->selected = 0;
  }

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static char* iFlatTreeGetMarkModeAttrib(Ihandle* ih)
{
  if (ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
    return "SINGLE";
  else
    return "MULTIPLE";
}

static int iFlatTreeSetMarkModeAttrib(Ihandle* ih, const char* value)
{
	if (iupStrEqualNoCase(value, "MULTIPLE"))
  {
		ih->data->mark_mode = IFLATTREE_MARK_MULTIPLE;
    ih->data->show_dragdrop = 0;
  }
  else
  {
    ih->data->mark_mode = IFLATTREE_MARK_SINGLE;

    iFlatTreeClearAllSelectionExcept(ih, NULL);
  }

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static int iFlatTreeSetImageAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->image)
    free(node->image);
  node->image = iupStrDup(value);

  iFlatTreeUpdateNodeSize(ih, node);
  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetImageAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->image;
}

static int iFlatTreeSetImageExpandedAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->image_expanded)
    free(node->image_expanded);
  node->image_expanded = iupStrDup(value);

  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetImageExpandedAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->image_expanded;
}

static char* iFlatTreeGetShowDragDropAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->show_dragdrop);
}

static int iFlatTreeSetShowDragDropAttrib(Ihandle* ih, const char* value)
{
  if (iupStrBoolean(value) && ih->data->mark_mode == IFLATTREE_MARK_SINGLE)
    ih->data->show_dragdrop = 1;
  else
    ih->data->show_dragdrop = 0;

  return 0;
}

static int iFlatTreeSetDragDropTreeAttrib(Ihandle* ih, const char* value)
{
  if (iupStrBoolean(value))
  {
    /* Register callbacks to enable drag and drop between trees, DRAG&DROP attributes must still be set by the application */
    IupSetCallback(ih, "DRAGBEGIN_CB", (Icallback)iFlatTreeDragBegin_CB);
    IupSetCallback(ih, "DRAGDATASIZE_CB", (Icallback)iFlatTreeDragDataSize_CB);
    IupSetCallback(ih, "DRAGDATA_CB", (Icallback)iFlatTreeDragData_CB);
    IupSetCallback(ih, "DRAGEND_CB", (Icallback)iFlatTreeDragEnd_CB);
    IupSetCallback(ih, "DROPDATA_CB", (Icallback)iFlatTreeDropData_CB);
  }
  else
  {
    /* Unregister callbacks */
    IupSetCallback(ih, "DRAGBEGIN_CB", NULL);
    IupSetCallback(ih, "DRAGDATASIZE_CB", NULL);
    IupSetCallback(ih, "DRAGDATA_CB", NULL);
    IupSetCallback(ih, "DRAGEND_CB", NULL);
    IupSetCallback(ih, "DROPDATA_CB", NULL);
  }

  return 1;
}

static int iFlatTreeSetIconSpacingAttrib(Ihandle* ih, const char* value)
{
  iupStrToInt(value, &ih->data->icon_spacing);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}

static char* iFlatTreeGetIconSpacingAttrib(Ihandle *ih)
{
  return iupStrReturnInt(ih->data->icon_spacing);
}

static char* iFlatTreeGetCountAttrib(Ihandle* ih)
{
  return iupStrReturnInt(iupArrayCount(ih->data->node_array));
}

static char* iFlatTreeGetChildCountAttrib(Ihandle* ih, int id)
{
  int count;
  iFlatTreeNode *child;
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  count = 0;
  child = node->first_child;
  while (child != NULL)
  {
    count++;
    child = child->brother;
  }

  return iupStrReturnInt(count);
}

static int iFlatTreeGetChildCount(iFlatTreeNode *node)
{
  int count = 0;
  iFlatTreeNode *child = node->first_child;

  while (child)
  {
    if (child->first_child)
      count += iFlatTreeGetChildCount(child);
    count++;
    child = child->brother;
  }

  return count;
}

static char* iFlatTreeGetTotalChildCountAttrib(Ihandle* ih, int id)
{
  int count;
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  count = iFlatTreeGetChildCount(node);

  return iupStrReturnInt(count);
}

static char* iFlatTreeGetRootCountAttrib(Ihandle* ih)
{
  int count;
  iFlatTreeNode *brother;
  iFlatTreeNode *node = iFlatTreeGetNode(ih, 0);
  if (!node)
    return "0";

  brother = node->brother;

  count = 1;
  while (brother)
  {
    count++;
    brother = brother->brother;
  }

  return iupStrReturnInt(count);
}

static char* iFlatTreeGetDepthAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return iupStrReturnInt(node->depth);
}

static char* iFlatTreeGetColorAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->fg_color;
}

static int iFlatTreeSetColorAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->fg_color)
    free(node->fg_color);
  node->fg_color = iupStrDup(value);

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static char* iFlatTreeGetBackColorAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->bg_color;
}

static int iFlatTreeSetBackColorAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->bg_color)
    free(node->bg_color);
  node->bg_color = iupStrDup(value);

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static char* iFlatTreeGetTipAttrib(Ihandle* ih, int id)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return NULL;

  return node->tip;
}

static int iFlatTreeSetTipAttrib(Ihandle* ih, int id, const char* value)
{
  iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
  if (!node)
    return 0;

  if (node->tip)
    free(node->tip);
  node->tip = iupStrDup(value);

  iFlatTreeRedraw(ih, 0, 0);
  return 0;
}

static int iFlatTreeSetTopItemAttrib(Ihandle* ih, const char* value)
{
  int id = 0;
  if (iupStrToInt(value, &id))
  {
    int node_y;

    iFlatTreeNode *node = iFlatTreeGetNode(ih, id);
    if (!node)
      return 0;

    node_y = iFlatTreeGetNodeY(ih, node);
    IupSetInt(ih, "POSY", node_y);

    iFlatTreeRedraw(ih, 0, 0);
  }
  return 0;
}

static char* iFlatTreeGetShowRenameAttrib(Ihandle* ih)
{
  return iupStrReturnBoolean(ih->data->show_rename);
}

static int iFlatTreeSetShowRenameAttrib(Ihandle* ih, const char* value)
{
  if (iupStrBoolean(value))
    ih->data->show_rename = 1;
  else
    ih->data->show_rename = 0;

  return 0;
}

static int iFlatTreeWheel_CB(Ihandle* ih, float delta)
{
  if (iupFlatScrollBarGet(ih) != IUP_SB_NONE)
    iupFlatScrollBarWheelUpdate(ih, delta);
  return IUP_DEFAULT;
}

static int iFlatTreeSetFlatScrollbarAttrib(Ihandle* ih, const char* value)
{
  /* can only be set before map */
  if (ih->handle)
    return IUP_DEFAULT;

  if (value && !iupStrEqualNoCase(value, "NO"))
  {
    if (iupFlatScrollBarCreate(ih))
    {
      IupSetAttribute(ih, "SCROLLBAR", "NO");
      IupSetCallback(ih, "WHEEL_CB", (Icallback)iFlatTreeWheel_CB);
    }
    return 1;
  }
  else
    return 0;
}

static int iFlatTreeSetBorderWidthAttrib(Ihandle* ih, const char* value)
{
  iupStrToInt(value, &ih->data->border_width);
  iFlatTreeRedraw(ih, 0, 1);
  return 0;
}

static char* iFlatTreeGetBorderWidthAttrib(Ihandle *ih)
{
  return iupStrReturnInt(ih->data->border_width);
}

static int iFlatTreeSetAttribPostRedraw(Ihandle* ih, const char* value)
{
  (void)value;
  if (ih->data->auto_redraw)
    IupUpdate(ih); /* redraw after the atribute is saved on the hash table */
  return 1;
}

static int iFlatTreeSetImageLeafAttrib(Ihandle* ih, const char* value)
{
  if (ih->data->auto_redraw)
  {
    iupAttribSetStr(ih, "IMAGELEAF", value);  /* pre-save to be able to calculate size before redraw */
    iFlatTreeRedraw(ih, 1, 1);
  }

  return 1;
}

static int iFlatTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value)
{
  if (ih->data->auto_redraw)
  {
    iupAttribSetStr(ih, "IMAGEBRANCHCOLLAPSED", value);
    iFlatTreeRedraw(ih, 1, 1);
  }

  return 1;
}

static char* iFlatTreeGetExtraTextWidthAttrib(Ihandle* ih)
{
  return iupStrReturnInt(ih->data->extratext_width);
}

static int iFlatTreeSetExtraTextWidthAttrib(Ihandle* ih, const char* value)
{
  iupStrToInt(value, &ih->data->extratext_width);
  iFlatTreeRedraw(ih, 1, 1);
  return 0;
}
static char* iFlatTreeGetExtraTextAttrib(Ihandle* ih, int id)
{
	iFlatTreeNode *node = (iFlatTreeNode *)iFlatTreeGetNode(ih, id);
	if (!node)
		return NULL;

	return node->extratext;
}

static int iFlatTreeSetExtraTextAttrib(Ihandle* ih, int id, const char* value) 
{
	iFlatTreeNode *node = (iFlatTreeNode *)iFlatTreeGetNode(ih, id);
	if (!node)
		return 0;

  if (node->extratext)
    free(node->extratext);
	node->extratext = iupStrDup(value);

	iFlatTreeRedraw(ih, 0, 1);
	return 0;
}

/*********************************  Methods  ************************************/


static void iFlatTreeSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink)
{
  if (iupFlatScrollBarGet(ih) != IUP_SB_NONE)
    iupFlatScrollBarSetChildrenCurrentSize(ih, shrink);
}

static void iFlatTreeSetChildrenPositionMethod(Ihandle* ih, int x, int y)
{
  if (iupFlatScrollBarGet(ih) != IUP_SB_NONE)
    iupFlatScrollBarSetChildrenPosition(ih);

  (void)x;
  (void)y;
}

static void iFlatTreeDestroyMethod(Ihandle* ih)
{
  if (ih->data->root_node->first_child)
  {
    IFns noderemoved_cb = (IFns)IupGetCallback(ih, "NODEREMOVED_CB");
    iFlatTreeRemoveNode(ih, ih->data->root_node->first_child, noderemoved_cb);
  }

  iupFlatScrollBarRelease(ih);

  iupArrayDestroy(ih->data->node_array);

  free(ih->data->root_node);
}

static int iFlatTreeCreateMethod(Ihandle* ih, void** params)
{
  Ihandle* text;
  int high_dpi = iupIsHighDpi();
  (void)params;

  if (IupGetInt(NULL, "TREEIMAGE24"))
  {
    high_dpi = 1;
    iupAttribSet(ih, "IMAGELEAF", "IMGLEAF24");
    iupAttribSet(ih, "IMAGEBRANCHCOLLAPSED", "IMGCOLLAPSED24");
    iupAttribSet(ih, "IMAGEBRANCHEXPANDED", "IMGEXPANDED24");
  }

  /* free the data allocated by IupCanvas, and reallocate */
  free(ih->data);
  ih->data = iupALLOCCTRLDATA();

  text = IupText(NULL);
  text->currentwidth = 20;  /* just to avoid initial size 0x0 */
  text->currentheight = 10;
  text->flags |= IUP_INTERNAL;
  iupChildTreeAppend(ih, text);

  IupSetCallback(text, "VALUECHANGED_CB", (Icallback)iFlatTreeTextEditVALUECHANGED_CB);
  IupSetCallback(text, "KILLFOCUS_CB", (Icallback)iFlatTreeTextEditKILLFOCUS_CB);
  IupSetCallback(text, "K_ESC", (Icallback)iFlatTreeTextEditKEsc_CB);
  IupSetCallback(text, "K_CR", (Icallback)iFlatTreeTextEditKCR_CB);
  IupSetAttribute(text, "FLOATING", "IGNORE");
  IupSetAttribute(text, "VISIBLE", "NO");
  IupSetAttribute(text, "ACTIVE", "NO");

  /* non zero default values */
  ih->data->auto_redraw = 1;
  ih->data->icon_spacing = 2;
  ih->data->add_expanded = 1;
  ih->data->indentation = high_dpi? 24 : 16;
  ih->data->toggle_size = ih->data->indentation;
  ih->data->button_size = high_dpi ? 16 : 9;
  ih->data->dragover_id = -1;
  ih->data->dragged_id = -1;
  ih->data->last_selected_id = -1;

  ih->data->root_node = (iFlatTreeNode*)malloc(sizeof(iFlatTreeNode));
  memset(ih->data->root_node, 0, sizeof(iFlatTreeNode));
  ih->data->root_node->id = -1;
  ih->data->root_node->depth = -1;
  ih->data->root_node->kind = IFLATTREE_BRANCH;
  ih->data->root_node->state = IFLATTREE_EXPANDED;
  ih->data->root_node->expanded = 1;

  ih->data->node_array = iupArrayCreate(10, sizeof(iFlatTreeNode*));

  IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)iFlatTreeConvertXYToId);
  IupSetCallback(ih, "_IUPTREE_FIND_USERDATA_CB", (Icallback)iFlatTreeFindUserDataId);

  /* internal callbacks */
  IupSetCallback(ih, "ACTION", (Icallback)iFlatTreeRedraw_CB);
  IupSetCallback(ih, "BUTTON_CB", (Icallback)iFlatTreeButton_CB);
  IupSetCallback(ih, "MOTION_CB", (Icallback)iFlatTreeMotion_CB);
  IupSetCallback(ih, "LEAVEWINDOW_CB", (Icallback)iFlatTreeLeaveWindow_CB);
  IupSetCallback(ih, "RESIZE_CB", (Icallback)iFlatTreeResize_CB);
  IupSetCallback(ih, "FOCUS_CB", (Icallback)iFlatTreeFocus_CB);
  IupSetCallback(ih, "SCROLL_CB", (Icallback)iFlatTreeScroll_CB);
  IupSetCallback(ih, "K_CR", (Icallback)iFlatTreeKCr_CB);
  IupSetCallback(ih, "K_UP", (Icallback)iFlatTreeKUp_CB);
  IupSetCallback(ih, "K_sUP", (Icallback)iFlatTreeKUp_CB);
  IupSetCallback(ih, "K_cUP", (Icallback)iFlatTreeKUp_CB);
  IupSetCallback(ih, "K_DOWN", (Icallback)iFlatTreeKDown_CB);
  IupSetCallback(ih, "K_sDOWN", (Icallback)iFlatTreeKDown_CB);
  IupSetCallback(ih, "K_cDOWN", (Icallback)iFlatTreeKDown_CB);
  IupSetCallback(ih, "K_HOME", (Icallback)iFlatTreeKHome_CB);
  IupSetCallback(ih, "K_sHOME", (Icallback)iFlatTreeKHome_CB);
  IupSetCallback(ih, "K_END", (Icallback)iFlatTreeKEnd_CB);
  IupSetCallback(ih, "K_sEND", (Icallback)iFlatTreeKEnd_CB);
  IupSetCallback(ih, "K_PGUP", (Icallback)iFlatTreeKPgUp_CB);
  IupSetCallback(ih, "K_sPGUP", (Icallback)iFlatTreeKPgUp_CB);
  IupSetCallback(ih, "K_PGDN", (Icallback)iFlatTreeKPgDn_CB);
  IupSetCallback(ih, "K_sPGDN", (Icallback)iFlatTreeKPgDn_CB);
  IupSetCallback(ih, "K_cSP", (Icallback)iFlatTreeKcSpace_CB);
  IupSetCallback(ih, "K_F2", (Icallback)iFlatTreeKF2_CB);

  return IUP_NOERROR;
}


/******************************************************************************/


IUP_API Ihandle* IupFlatTree(void)
{
  return IupCreate("flattree");
}

Iclass* iupFlatTreeNewClass(void)
{
  Iclass* ic = iupClassNew(iupRegisterFindClass("canvas"));

  ic->name = "flattree";
  ic->format = NULL;  /* no parameters */
  ic->nativetype = IUP_TYPECANVAS;
  ic->childtype = IUP_CHILDNONE;
  ic->is_interactive = 1;
  ic->has_attrib_id = 1;

  /* Class functions */
  ic->New = iupFlatTreeNewClass;
  ic->Create = iFlatTreeCreateMethod;
  ic->Destroy = iFlatTreeDestroyMethod;
  ic->SetChildrenCurrentSize = iFlatTreeSetChildrenCurrentSizeMethod;
  ic->SetChildrenPosition = iFlatTreeSetChildrenPositionMethod;

  /* Callbacks */
  iupClassRegisterCallback(ic, "TOGGLEVALUE_CB", "ii");
  iupClassRegisterCallback(ic, "SELECTION_CB", "ii");
  iupClassRegisterCallback(ic, "MULTISELECTION_CB", "Ii");
  iupClassRegisterCallback(ic, "MULTIUNSELECTION_CB", "Ii");
  iupClassRegisterCallback(ic, "BRANCHOPEN_CB", "i");
  iupClassRegisterCallback(ic, "BRANCHCLOSE_CB", "i");
  iupClassRegisterCallback(ic, "EXECUTELEAF_CB", "i");
  iupClassRegisterCallback(ic, "EXECUTEBRANCH_CB", "i");
  iupClassRegisterCallback(ic, "SHOWRENAME_CB", "i");
  iupClassRegisterCallback(ic, "RENAME_CB", "is");
  iupClassRegisterCallback(ic, "DRAGDROP_CB", "iiii");
  iupClassRegisterCallback(ic, "RIGHTCLICK_CB", "i");
  iupClassRegisterCallback(ic, "NODEREMOVED_CB", "s");
  iupClassRegisterCallback(ic, "FLAT_BUTTON_CB", "iiiis");
  iupClassRegisterCallback(ic, "FLAT_MOTION_CB", "iis");
  iupClassRegisterCallback(ic, "FLAT_FOCUS_CB", "i");
  iupClassRegisterCallback(ic, "FLAT_LEAVEWINDOW_CB", "");

  iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupFlatSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
  iupClassRegisterAttribute(ic, "TIP", NULL, iupFlatItemSetTipAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);

  /* General Attributes */
  iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, IUP_FLAT_FORECOLOR, IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, IUP_FLAT_BACKCOLOR, IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "HLCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTHLCOLOR", IUPAF_NO_INHERIT);  /* selection box, not highlight */
  iupClassRegisterAttribute(ic, "HLCOLORALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "128", IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "PSCOLOR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);  /* selection, not pressed */
  iupClassRegisterAttribute(ic, "TEXTPSCOLOR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);  /* selection, not pressed */
  iupClassRegisterAttribute(ic, "INDENTATION", iFlatTreeGetIndentationAttrib, iFlatTreeSetIndentationAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "SPACING", iFlatTreeGetSpacingAttrib, iFlatTreeSetSpacingAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "CSPACING", iupBaseGetCSpacingAttrib, iupBaseSetCSpacingAttrib, NULL, NULL, IUPAF_NO_SAVE | IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "AUTOREDRAW", iFlatTreeGetAutoRedrawAttrib, iFlatTreeSetAutoRedrawAttrib, IUPAF_SAMEASSYSTEM, "Yes", IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BORDERCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, IUP_FLAT_BORDERCOLOR, IUPAF_NOT_MAPPED | IUPAF_DEFAULT);  /* inheritable */
  iupClassRegisterAttribute(ic, "BORDERWIDTH", iFlatTreeGetBorderWidthAttrib, iFlatTreeSetBorderWidthAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED);  /* inheritable */
  iupClassRegisterAttribute(ic, "ICONSPACING", iFlatTreeGetIconSpacingAttrib, iFlatTreeSetIconSpacingAttrib, IUPAF_SAMEASSYSTEM, "2", IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TOPITEM", NULL, iFlatTreeSetTopItemAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);

  /* Expanders */
  iupClassRegisterAttribute(ic, "BUTTONSIZE", iFlatTreeGetButtonSizeAttrib, iFlatTreeSetButtonSizeAttrib, NULL, NULL, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "HIDELINES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "HIDEBUTTONS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BUTTONBGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "240 240 240", IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "BUTTONFGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "50 100 150", IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "BUTTONBRDCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "150 150 150", IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "LINECOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "110 110 110", IUPAF_NOT_MAPPED);

  /* Editing */
  iupClassRegisterAttribute(ic, "SHOWRENAME", iFlatTreeGetShowRenameAttrib, iFlatTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "RENAME", NULL, iFlatTreeSetRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "RENAMECARET", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "RENAMESELECTION", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);

  /* Nodes */
  iupClassRegisterAttribute(ic, "COUNT", iFlatTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_READONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "ROOTCOUNT", iFlatTreeGetRootCountAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "CHILDCOUNT", iFlatTreeGetChildCountAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "TOTALCHILDCOUNT", iFlatTreeGetTotalChildCountAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "COLOR", iFlatTreeGetColorAttrib, iFlatTreeSetColorAttrib, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "BACKCOLOR", iFlatTreeGetBackColorAttrib, iFlatTreeSetBackColorAttrib, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "ITEMTIP", iFlatTreeGetTipAttrib, iFlatTreeSetTipAttrib, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "DEPTH", iFlatTreeGetDepthAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "KIND", iFlatTreeGetKindAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "PARENT", iFlatTreeGetParentAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "NEXT", iFlatTreeGetNextAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "PREVIOUS", iFlatTreeGetPreviousAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "LAST", iFlatTreeGetLastAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "FIRST", iFlatTreeGetFirstAttrib, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "STATE", iFlatTreeGetStateAttrib, iFlatTreeSetStateAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "TITLE", iFlatTreeGetTitleAttrib, iFlatTreeSetTitleAttrib, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "TITLEFONT", iFlatTreeGetTitleFontAttrib, iFlatTreeSetTitleFontAttrib, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "TITLEFONTSTYLE", iFlatTreeGetTitleFontStyleAttrib, iFlatTreeSetTitleFontStyleAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "TITLEFONTSIZE", iFlatTreeGetTitleFontSizeAttrib, iFlatTreeSetTitleFontSizeAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "USERDATA", iFlatTreeGetUserDataAttrib, iFlatTreeSetUserDataAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_STRING | IUPAF_NO_INHERIT);

  /* Toggle */
  iupClassRegisterAttribute(ic, "SHOWTOGGLE", iFlatTreeGetShowToggleAttrib, iFlatTreeSetShowToggleAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TOGGLESIZE", iFlatTreeGetToggleSizeAttrib, iFlatTreeSetToggleSizeAttrib, NULL, NULL, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "EMPTYTOGGLE", iFlatTreeGetEmptyToggleAttrib, iFlatTreeSetEmptyToggleAttrib, NULL, NULL, IUPAF_NO_INHERIT | IUPAF_NOT_MAPPED);
  iupClassRegisterAttributeId(ic, "TOGGLEVALUE", iFlatTreeGetToggleValueAttrib, iFlatTreeSetToggleValueAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "TOGGLEVISIBLE", iFlatTreeGetToggleVisibleAttrib, iFlatTreeSetToggleVisibleAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TOGGLEBGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);
  iupClassRegisterAttribute(ic, "TOGGLEFGCOLOR", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED);

  /* Images */
  iupClassRegisterAttributeId(ic, "IMAGE", iFlatTreeGetImageAttrib, iFlatTreeSetImageAttrib, IUPAF_IHANDLENAME | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", iFlatTreeGetImageExpandedAttrib, iFlatTreeSetImageExpandedAttrib, IUPAF_IHANDLENAME | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, iFlatTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NOT_MAPPED | IUPAF_IHANDLENAME | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, iFlatTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NOT_MAPPED | IUPAF_IHANDLENAME | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, iFlatTreeSetAttribPostRedraw, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NOT_MAPPED | IUPAF_IHANDLENAME | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BACKIMAGE", NULL, iFlatTreeSetAttribPostRedraw, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_IHANDLENAME | IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BACKIMAGEZOOM", NULL, iFlatTreeSetAttribPostRedraw, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BUTTONPLUSIMAGE", NULL, iFlatTreeSetAttribPostRedraw, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "BUTTONMINUSIMAGE", NULL, iFlatTreeSetAttribPostRedraw, NULL, NULL, IUPAF_NO_INHERIT);

  /* Focus */
  iupClassRegisterAttribute(ic, "VALUE", iFlatTreeGetValueAttrib, iFlatTreeSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_SAVE | IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "HASFOCUS", iFlatTreeGetHasFocusAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "FOCUSFEEDBACK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);

  /* Marks */
  iupClassRegisterAttribute(ic, "MARK", NULL, iFlatTreeSetMarkAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "MARKED", iFlatTreeGetMarkedAttrib, iFlatTreeSetMarkedAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MARKEDNODES", iFlatTreeGetMarkedNodesAttrib, iFlatTreeSetMarkedNodesAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_SAVE | IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MARKMODE", iFlatTreeGetMarkModeAttrib, iFlatTreeSetMarkModeAttrib, IUPAF_SAMEASSYSTEM, "SINGLE", IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MARKSTART", iFlatTreeGetMarkStartAttrib, iFlatTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MARKWHENTOGGLE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);

  /* Hierarchy */
  iupClassRegisterAttribute(ic, "ADDEXPANDED", iFlatTreeGetAddExpandedAttrib, iFlatTreeSetAddExpandedAttrib, "YES", NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "ADDLEAF", NULL, iFlatTreeSetAddLeafAttrib, IUPAF_WRITEONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "ADDBRANCH", NULL, iFlatTreeSetAddBranchAttrib, IUPAF_WRITEONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "INSERTLEAF", NULL, iFlatTreeSetInsertLeafAttrib, IUPAF_WRITEONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "INSERTBRANCH", NULL, iFlatTreeSetInsertBranchAttrib, IUPAF_WRITEONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "COPYNODE", NULL, iFlatTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "DELNODE", NULL, iFlatTreeSetDelNodeAttrib, IUPAF_WRITEONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "MOVENODE", NULL, iFlatTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "LASTADDNODE", iFlatTreeGetLastAddNodeAttrib, NULL, IUPAF_SAMEASSYSTEM, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "EXPANDALL", NULL, iFlatTreeSetExpandAllAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_WRITEONLY | IUPAF_NO_INHERIT);

  /* Drag&Drop */
  iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iFlatTreeGetShowDragDropAttrib, iFlatTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "DRAGDROPTREE", NULL, iFlatTreeSetDragDropTreeAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "DROPEQUALDRAG", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);

  /* External Text */
  iupClassRegisterAttribute(ic, "EXTRATEXTWIDTH", iFlatTreeGetExtraTextWidthAttrib, iFlatTreeSetExtraTextWidthAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
  iupClassRegisterAttributeId(ic, "EXTRATEXT", iFlatTreeGetExtraTextAttrib, iFlatTreeSetExtraTextAttrib, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);
  /* Scrollbars */
  iupClassRegisterReplaceAttribDef(ic, "SCROLLBAR", "YES", NULL);  /* change the default to Yes */
  iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);  /* will be always Yes */
  iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY | IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);  /* will be always Yes */

  iupFlatScrollBarRegister(ic);
  iupClassRegisterAttribute(ic, "FLATSCROLLBAR", NULL, iFlatTreeSetFlatScrollbarAttrib, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_NO_INHERIT);

  iFlatTreeInitializeImages();

  return ic;
}

/*Reflection:
    "iFlatTreeNode* could be replaced by an Ihandle* and then exported to the application"
  PROS
    more flexibility for managing the nodes and its attributes
    the application can store a pointer to a node
  CONS
    Ihandle* has a memory overhead much larger than iFlatTreeNode
    node attributes and almost all aux must be consulted using functions
*/
