
#include "simple_paint.h"
#include "simple_paint_util.h"

#include <stdio.h>
#include <stdlib.h>

#include <im_process.h>
#include <iup_config.h>
#include <iupim.h>
#include <im_lib.h>
#include <cd.h>



/********************************** Images *****************************************/


static Ihandle* load_image_PaintZoomGrid(void)
{
  unsigned char imgdata[] = {
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 110, 155, 223, 255, 255, 255, 255, 0, 255, 255, 255, 0, 106, 151, 219, 255, 255, 255, 255, 0, 255, 255, 255, 0, 95, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 129, 201, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 110, 155, 223, 255, 255, 255, 255, 0, 255, 255, 255, 0, 102, 147, 217, 255, 255, 255, 255, 0, 255, 255, 255, 0, 92, 137, 207, 255, 255, 255, 255, 0, 255, 255, 255, 0, 80, 125, 197, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 110, 155, 223, 255, 110, 155, 223, 255, 107, 152, 222, 255, 104, 151, 219, 255, 103, 148, 216, 255, 100, 145, 213, 255, 97, 142, 210, 255, 93, 138, 206, 255, 88, 133, 203, 255, 84, 129, 201, 255, 80, 125, 197, 255, 76, 121, 193, 255, 72, 117, 189, 255, 68, 113, 183, 255, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 106, 149, 219, 255, 255, 255, 255, 0, 255, 255, 255, 0, 97, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 131, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 103, 148, 216, 255, 255, 255, 255, 0, 255, 255, 255, 0, 92, 137, 207, 255, 255, 255, 255, 0, 255, 255, 255, 0, 81, 125, 196, 255, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 104, 151, 219, 255, 104, 148, 216, 255, 100, 145, 213, 255, 97, 142, 210, 255, 92, 137, 207, 255, 88, 135, 203, 255, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 193, 255, 70, 117, 189, 255, 68, 112, 183, 255, 62, 109, 181, 255, 60, 105, 177, 255, 57, 102, 174, 255, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 97, 142, 210, 255, 255, 255, 255, 0, 255, 255, 255, 0, 84, 129, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 105, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 93, 138, 206, 255, 255, 255, 255, 0, 255, 255, 255, 0, 80, 125, 195, 255, 255, 255, 255, 0, 255, 255, 255, 0, 66, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 56, 103, 173, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 95, 140, 212, 255, 92, 137, 207, 255, 88, 133, 203, 255, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 193, 255, 72, 117, 187, 255, 68, 113, 185, 255, 64, 107, 181, 255, 59, 105, 178, 255, 55, 101, 174, 255, 53, 98, 170, 255, 49, 95, 168, 255, 48, 91, 165, 255, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 84, 131, 199, 255, 255, 255, 255, 0, 255, 255, 255, 0, 70, 117, 189, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 105, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 49, 95, 168, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 82, 125, 195, 255, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 57, 102, 174, 255, 255, 255, 255, 0, 255, 255, 255, 0, 46, 92, 165, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 84, 129, 199, 255, 80, 125, 195, 255, 76, 121, 191, 255, 72, 117, 189, 255, 66, 113, 185, 255, 64, 109, 181, 255, 60, 105, 177, 255, 55, 102, 174, 255, 52, 98, 171, 255, 49, 95, 168, 255, 46, 91, 166, 255, 44, 90, 163, 255, 42, 88, 161, 255, 42, 88, 161, 255, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 72, 117, 187, 255, 255, 255, 255, 0, 255, 255, 255, 0, 60, 107, 177, 255, 255, 255, 255, 0, 255, 255, 255, 0, 50, 95, 167, 255, 255, 255, 255, 0, 255, 255, 255, 0, 42, 88, 161, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 68, 113, 185, 255, 255, 255, 255, 0, 255, 255, 255, 0, 56, 101, 173, 255, 255, 255, 255, 0, 255, 255, 255, 0, 46, 92, 165, 255, 255, 255, 255, 0, 255, 255, 255, 0, 42, 88, 161, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
    255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0 };

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


/*********************************** Utilities Methods **************************************/

                     
void SimplePaint::UpdateImage(imImage* new_image, bool update_size)
{
  file.SetImage(new_image);

  if (update_size)
  {
    Ihandle* size_lbl = IupGetDialogChild(dlg, "SIZELABEL");
    IupSetfAttribute(size_lbl, "TITLE", "%d x %d px", file.GetImage()->width, file.GetImage()->height);

    canvas.ScrollUpdate();
  }

  canvas.Update();
}

void SimplePaint::UpdateFile()
{
  Ihandle* size_lbl = IupGetDialogChild(dlg, "SIZELABEL");

  if (file.GetFilename())
    IupSetfAttribute(dlg, "TITLE", "%s - Simple Paint", str_filetitle(file.GetFilename()));
  else
    IupSetAttribute(dlg, "TITLE", "Untitled - Simple Paint");

  IupSetfAttribute(size_lbl, "TITLE", "%d x %d px", file.GetImage()->width, file.GetImage()->height);

  /* reset zoom to 100% */
  canvas.SetZoom(0);
}

void SimplePaint::CheckNewFile()
{
  if (!file.GetImage())
  {
    int width = IupConfigGetVariableIntDef(config, "NewImage", "Width", 640);
    int height = IupConfigGetVariableIntDef(config, "NewImage", "Height", 480);

    if (file.New(width, height))
      UpdateFile();
  }
}

void SimplePaint::OpenFile(const char* filename)
{
  if (file.Open(filename))
  {
    UpdateFile();

    IupConfigRecentUpdate(config, filename);
  }
}

void SimplePaint::ToggleBarVisibility(Ihandle* item, Ihandle* bar)
{
  if (IupGetInt(bar, "VISIBLE"))
  {
    IupSetAttribute(bar, "FLOATING", "YES");
    IupSetAttribute(bar, "VISIBLE", "NO");
    IupSetAttribute(item, "VALUE", "OFF");
  }
  else
  {
    IupSetAttribute(bar, "FLOATING", "NO");
    IupSetAttribute(bar, "VISIBLE", "YES");
    IupSetAttribute(item, "VALUE", "ON");
  }

  IupRefresh(bar);  /* refresh the dialog layout */
}

void SimplePaint::SelectFile(bool is_open)
{
  const char* dir = IupConfigGetVariableStr(config, "MainWindow", "LastDirectory");

  Ihandle* filedlg = IupFileDlg();
  if (is_open)
    IupSetAttribute(filedlg, "DIALOGTYPE", "OPEN");
  else
  {
    IupSetAttribute(filedlg, "DIALOGTYPE", "SAVE");
    IupSetStrAttribute(filedlg, "FILE", file.GetFilename());
  }
  IupSetAttribute(filedlg, "EXTFILTER", "Image Files|*.bmp;*.jpg;*.png;*.tif;*.tga|All Files|*.*|");
  IupSetStrAttribute(filedlg, "DIRECTORY", dir);
  IupSetAttributeHandle(filedlg, "PARENTDIALOG", dlg);

  IupPopup(filedlg, IUP_CENTERPARENT, IUP_CENTERPARENT);
  if (IupGetInt(filedlg, "STATUS") != -1)
  {
    char* filename = IupGetAttribute(filedlg, "VALUE");
    if (is_open)
      OpenFile(filename);
    else
    {
      if (file.SaveAsFile(filename))
      {
        IupSetfAttribute(dlg, "TITLE", "%s - Simple Paint", str_filetitle(filename));
        IupConfigRecentUpdate(config, filename);
      }
    }

    dir = IupGetAttribute(filedlg, "DIRECTORY");
    IupConfigSetVariableStr(config, "MainWindow", "LastDirectory", dir);
  }

  IupDestroy(filedlg);
}


/********************************** Callbacks Methods *****************************************/


int SimplePaint::ZoomValueChangedCallback(Ihandle* val)
{
  double zoom_index = IupGetDouble(val, "VALUE");
  canvas.SetZoom(zoom_index);
  return IUP_DEFAULT;
}

int SimplePaint::DialogDropfilesCallback(Ihandle*, char* filename)
{
  if (file.SaveCheck())
    OpenFile(filename);

  return IUP_DEFAULT;
}

int SimplePaint::FileMenuOpenCallback(Ihandle*)
{
  Ihandle* item_save = IupGetDialogChild(dlg, "ITEM_SAVE");
  if (file.GetImageChanged())
    IupSetAttribute(item_save, "ACTIVE", "YES");
  else
    IupSetAttribute(item_save, "ACTIVE", "NO");

  Ihandle* item_revert = IupGetDialogChild(dlg, "ITEM_REVERT");
  if (file.GetImageChanged() && file.GetFilename())
    IupSetAttribute(item_revert, "ACTIVE", "YES");
  else
    IupSetAttribute(item_revert, "ACTIVE", "NO");
  return IUP_DEFAULT;
}

int SimplePaint::EditMenuOpenCallback(Ihandle*)
{
  Ihandle *clipboard = IupClipboard(); 

  Ihandle *item_paste = IupGetDialogChild(dlg, "ITEM_PASTE");

  if (!IupGetInt(clipboard, "IMAGEAVAILABLE"))
    IupSetAttribute(item_paste, "ACTIVE", "NO");
  else
    IupSetAttribute(item_paste, "ACTIVE", "YES");

  IupDestroy(clipboard);
  return IUP_DEFAULT;
}

int SimplePaint::ViewMenuOpenCallback(Ihandle*)
{
  Ihandle* item_zoomgrid = IupGetDialogChild(dlg, "ITEM_ZOOMGRID");
  if (canvas.GetZoomGrid())
    IupSetAttribute(item_zoomgrid, "VALUE", "ON");
  else
    IupSetAttribute(item_zoomgrid, "VALUE", "OFF");

  Ihandle* item_toolbox = IupGetDialogChild(dlg, "ITEM_TOOLBOX");
  if (toolbox.Visible())
    IupSetAttribute(item_toolbox, "VALUE", "ON");
  else
    IupSetAttribute(item_toolbox, "VALUE", "OFF");

  Ihandle* item_toolbar = IupGetDialogChild(dlg, "ITEM_TOOLBAR");
  Ihandle* toolbar = IupGetDialogChild(dlg, "TOOLBAR");
  if (IupGetInt(toolbar, "VISIBLE"))
    IupSetAttribute(item_toolbar, "VALUE", "ON");
  else
    IupSetAttribute(item_toolbar, "VALUE", "OFF");

  Ihandle* item_statusbar = IupGetDialogChild(dlg, "ITEM_STATUSBAR");
  Ihandle* statusbar = IupGetDialogChild(dlg, "STATUSBAR");
  if (IupGetInt(statusbar, "VISIBLE"))
    IupSetAttribute(item_statusbar, "VALUE", "ON");
  else
    IupSetAttribute(item_statusbar, "VALUE", "OFF");

  return IUP_DEFAULT;
}

int SimplePaint::ConfigRecentCallback(Ihandle* ih)
{
  if (file.SaveCheck())
  {
    char* filename = IupGetAttribute(ih, "RECENTFILENAME");
    OpenFile(filename);
  }
  return IUP_DEFAULT;
}

int SimplePaint::DialogMoveCallback(Ihandle* dlg, int x, int y)
{
  int old_x = IupGetInt(dlg, "_OLD_X");
  int old_y = IupGetInt(dlg, "_OLD_Y");

  if (old_x == x && old_y == y)
    return IUP_DEFAULT;

  toolbox.MoveDialog(x - old_x, y - old_y);

  IupSetInt(dlg, "_OLD_X", x);
  IupSetInt(dlg, "_OLD_Y", y);

  return IUP_DEFAULT;
}


/********************************* SimplePaint Menu Item Callbacks Methods **************************/


int SimplePaint::ItemNewActionCallback(Ihandle*)
{
  if (file.SaveCheck())
  {
    int width = IupConfigGetVariableIntDef(config, "NewImage", "Width", 640);
    int height = IupConfigGetVariableIntDef(config, "NewImage", "Height", 480);

    if (IupGetParam("New Image", NULL, NULL, "Width: %i[1,]\nHeight: %i[1,]\n", &width, &height, NULL))
    {
      IupConfigSetVariableInt(config, "NewImage", "Width", width);
      IupConfigSetVariableInt(config, "NewImage", "Height", height);

      file.New(width, height);

      UpdateFile();
    }
  }

  return IUP_DEFAULT;
}

int SimplePaint::ItemOpenActionCallback(Ihandle*)
{
  if (!file.SaveCheck())
    return IUP_DEFAULT;

  SelectFile(true);
  return IUP_DEFAULT;
}

int SimplePaint::ItemSaveasActionCallback(Ihandle*)
{
  SelectFile(false);
  return IUP_DEFAULT;
}

int SimplePaint::ItemSaveActionCallback(Ihandle* item_save)
{
  if (!file.GetFilename())
    ItemSaveasActionCallback(item_save);
  else   
  {
    /* test again because in can be called using the hot key */
    if (file.GetImageChanged())
      file.SaveFile();
  }
  return IUP_DEFAULT;
}

int SimplePaint::ItemRevertActionCallback(Ihandle*)
{
  OpenFile(file.GetFilename());
  return IUP_DEFAULT;
}

int SimplePaint::ItemPagesetupActionCallback(Ihandle*)
{
  int margin_width = IupConfigGetVariableIntDef(config, "Print", "MarginWidth", 20);
  int margin_height = IupConfigGetVariableIntDef(config, "Print", "MarginHeight", 20);

  if (IupGetParam("Page Setup", NULL, NULL, "Margin Width (mm): %i[1,]\nMargin Height (mm): %i[1,]\n", &margin_width, &margin_height, NULL))
  {
    IupConfigSetVariableInt(config, "Print", "MarginWidth", margin_width);
    IupConfigSetVariableInt(config, "Print", "MarginHeight", margin_height);
  }

  return IUP_DEFAULT;
}

int SimplePaint::ItemPrintActionCallback(Ihandle*)
{
  char* title = IupGetAttribute(dlg, "TITLE");
  int margin_width = IupConfigGetVariableIntDef(config, "Print", "MarginWidth", 20);
  int margin_height = IupConfigGetVariableIntDef(config, "Print", "MarginHeight", 20);
  canvas.Print(title, margin_width, margin_height);
  return IUP_DEFAULT;
}

int SimplePaint::ItemExitActionCallback(Ihandle*)
{
  if (!file.SaveCheck())
    return IUP_IGNORE;  /* to abort the CLOSE_CB callback normal processing */

  IupConfigSetVariableStr(config, "MainWindow", "Toolbox", toolbox.Visible() ? "ON" : "OFF");
  if (toolbox.Visible())
    toolbox.HideDialog();  /* manually hide it before the main dialog, because it is a child dialog */

  file.Close();

  IupConfigDialogClosed(config, dlg, "MainWindow");
  IupConfigSave(config);
  IupDestroy(config);
  return IUP_CLOSE;
}

int SimplePaint::ItemCopyActionCallback(Ihandle*)
{
  Ihandle *clipboard = IupClipboard();
  IupSetAttribute(clipboard, "NATIVEIMAGE", NULL); /* clear clipboard first */
  IupSetAttribute(clipboard, "NATIVEIMAGE", (char*)IupGetImageNativeHandle(file.GetImage()));
  IupDestroy(clipboard);
  return IUP_DEFAULT;
}

int SimplePaint::ItemPasteActionCallback(Ihandle*)
{
  if (file.SaveCheck())
  {
    Ihandle *clipboard = IupClipboard();
    imImage* new_image = IupGetNativeHandleImage(IupGetAttribute(clipboard, "NATIVEIMAGE"));
    IupDestroy(clipboard);

    if (!new_image)
    {
      IupMessageError(NULL, "Invalid Clipboard Data");
      return IUP_DEFAULT;
    }

    file.New(new_image);

    UpdateFile();
  }
  return IUP_DEFAULT;
}

int SimplePaint::ItemBackgroundActionCallback(Ihandle*)
{
  Ihandle* colordlg = IupColorDlg();
  long background = canvas.GetBackground();
  IupSetRGB(colordlg, "VALUE", cdRed(background), cdGreen(background), cdBlue(background));
  IupSetAttributeHandle(colordlg, "PARENTDIALOG", dlg);

  IupPopup(colordlg, IUP_CENTERPARENT, IUP_CENTERPARENT);

  if (IupGetInt(colordlg, "STATUS") == 1)
  {
    const char* background_str = IupGetAttribute(colordlg, "VALUE");
    IupConfigSetVariableStr(config, "Canvas", "Background", background_str);

    unsigned int ri, gi, bi;
    sscanf(background_str, "%u %u %u", &ri, &gi, &bi);
    canvas.SetBackground(cdEncodeColor((unsigned char)ri, (unsigned char)gi, (unsigned char)bi));
  }

  IupDestroy(colordlg);
  return IUP_DEFAULT;
}

int SimplePaint::ItemZoomoutActionCallback(Ihandle*)
{
  canvas.ZoomOut();
  return IUP_DEFAULT;
}

int SimplePaint::ItemZoominActionCallback(Ihandle*)
{
  canvas.ZoomIn();
  return IUP_DEFAULT;
}

int SimplePaint::ItemActualsizeActionCallback(Ihandle*)
{
  canvas.SetZoom(0);
  return IUP_DEFAULT;
}

int SimplePaint::ItemZoomgridActionCallback(Ihandle*)
{
  canvas.SetZoomGrid(canvas.GetZoomGrid()? false: true);

  IupConfigSetVariableStr(config, "Canvas", "ZoomGrid", canvas.GetZoomGrid()? "ON": "OFF");

  return IUP_DEFAULT;
}

int SimplePaint::ItemToolbarActionCallback(Ihandle* item_toolbar)
{
  Ihandle* toolbar = IupGetDialogChild(dlg, "TOOLBAR");

  ToggleBarVisibility(item_toolbar, toolbar);

  IupConfigSetVariableStr(config, "MainWindow", "Toolbar", IupGetAttribute(item_toolbar, "VALUE"));
  return IUP_DEFAULT;
}

int SimplePaint::ItemToolboxActionCallback(Ihandle*)
{
  if (toolbox.Visible())
    toolbox.HideDialog();
  else
    toolbox.ShowDialog();
  return IUP_DEFAULT;
}

int SimplePaint::ItemStatusbarActionCallback(Ihandle* item_statusbar)
{
  Ihandle* statusbar = IupGetDialogChild(dlg, "STATUSBAR");

  ToggleBarVisibility(item_statusbar, statusbar);

  IupConfigSetVariableStr(config, "MainWindow", "Statusbar", IupGetAttribute(item_statusbar, "VALUE"));
  return IUP_DEFAULT;
}

int SimplePaint::ItemResizeActionCallback(Ihandle*)
{
  int height = file.GetImage()->height,
    width = file.GetImage()->width;
  int quality = IupConfigGetVariableIntDef(config, "Image", "ResizeQuality", 1);  /* medium default */

  if (!IupGetParam("Resize", NULL, NULL,
    "Width: %i[1,]\n"
    "Height: %i[1,]\n"
    "Quality: %l|low|medium|high|\n",
    &width, &height, &quality, NULL))
    return IUP_DEFAULT;

  IupConfigSetVariableInt(config, "Image", "ResizeQuality", quality);

  imImage* new_image = imImageCreateBased(file.GetImage(), width, height, -1, -1);
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  if (quality == 2)
    quality = 3; /* interpolation order can be 0, 1, and 3 */

  imProcessResize(file.GetImage(), new_image, quality);

  UpdateImage(new_image, true);   /* update size */

  return IUP_DEFAULT;
}

int SimplePaint::ItemMirrorActionCallback(Ihandle*)
{
  imImage* new_image = imImageClone(file.GetImage());
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessMirror(file.GetImage(), new_image);

  UpdateImage(new_image);

  return IUP_DEFAULT;
}

int SimplePaint::ItemFlipActionCallback(Ihandle*)
{
  imImage* new_image = imImageClone(file.GetImage());
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessFlip(file.GetImage(), new_image);

  UpdateImage(new_image);

  return IUP_DEFAULT;
}

int SimplePaint::ItemRotate180ActionCallback(Ihandle*)
{
  imImage* new_image = imImageClone(file.GetImage());
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessRotate180(file.GetImage(), new_image);

  UpdateImage(new_image);

  return IUP_DEFAULT;
}

int SimplePaint::ItemRotate90cwActionCallback(Ihandle*)
{
  imImage* new_image = imImageCreateBased(file.GetImage(), file.GetImage()->height, file.GetImage()->width, -1, -1);
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessRotate90(file.GetImage(), new_image, 1);

  UpdateImage(new_image, true);   /* update size */

  return IUP_DEFAULT;
}

int SimplePaint::ItemRotate90ccwActionCallback(Ihandle*)
{
  imImage* new_image = imImageCreateBased(file.GetImage(), file.GetImage()->height, file.GetImage()->width, -1, -1);
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessRotate90(file.GetImage(), new_image, -1);

  UpdateImage(new_image, true);   /* update size */

  return IUP_DEFAULT;
}

int SimplePaint::ItemNegativeActionCallback(Ihandle*)
{
  imImage* new_image = imImageClone(file.GetImage());
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  imProcessNegative(file.GetImage(), new_image);

  UpdateImage(new_image);

  return IUP_DEFAULT;
}

static int brightcont_param_cb(Ihandle* dialog, int param_index, void* user_data)
{
  Ihandle* dlg = (Ihandle*)user_data;

  if (param_index == 0 || param_index == 1)
  {
    imImage* image = (imImage*)IupGetAttribute(dlg, "ORIGINAL_IMAGE");
    imImage* new_image = (imImage*)IupGetAttribute(dlg, "NEW_IMAGE");
    SimplePaintFile* file = (SimplePaintFile*)IupGetAttribute(dlg, "PAINT_FILE");
    SimplePaintCanvas* canvas = (SimplePaintCanvas*)IupGetAttribute(dlg, "PAINT_CANVAS");
    Ihandle* brightness_shift_param = (Ihandle*)IupGetAttribute(dialog, "PARAM0");
    Ihandle* contrast_factor_param = (Ihandle*)IupGetAttribute(dialog, "PARAM1");

#if IM_VERSION_NUMBER > 312000
    double param[2] = { 0, 0 };
    param[0] = IupGetDouble(brightness_shift_param, "VALUE");
    param[1] = IupGetDouble(contrast_factor_param, "VALUE");
#else
    float param[2] = { 0, 0 };
    param[0] = IupGetFloat(brightness_shift_param, "VALUE");
    param[1] = IupGetFloat(contrast_factor_param, "VALUE");
#endif

    imProcessToneGamut(image, new_image, IM_GAMUT_BRIGHTCONT, param);

    file->SetImage(new_image, false);

    canvas->Update();
  }
  else if (param_index != IUP_GETPARAM_INIT && param_index != IUP_GETPARAM_MAP)
  {
    /* restore original configuration */
    SimplePaintFile* file = (SimplePaintFile*)IupGetAttribute(dlg, "PAINT_FILE");
    SimplePaintCanvas* canvas = (SimplePaintCanvas*)IupGetAttribute(dlg, "PAINT_CANVAS");
    imImage* image = (imImage*)IupGetAttribute(dlg, "ORIGINAL_IMAGE");

    file->SetImage(image, false);

    IupSetAttribute(dlg, "ORIGINAL_IMAGE", NULL);
    IupSetAttribute(dlg, "NEW_IMAGE", NULL);
    IupSetAttribute(dlg, "PAINT_FILE", NULL);
    IupSetAttribute(dlg, "PAINT_CANVAS", NULL);

    if (param_index == IUP_GETPARAM_BUTTON2)  /* cancel */
      canvas->Update();
  }

  return 1;
}

int SimplePaint::ItemBrightcontActionCallback(Ihandle*)
{
  imImage* new_image = imImageClone(file.GetImage());
  if (!new_image)
  {
    show_file_error(IM_ERR_MEM);
    return IUP_DEFAULT;
  }

  IupSetAttribute(dlg, "ORIGINAL_IMAGE", (char*)file.GetImage());
  IupSetAttribute(dlg, "NEW_IMAGE", (char*)new_image);
  IupSetAttribute(dlg, "PAINT_FILE", (char*)&file);
  IupSetAttribute(dlg, "PAINT_CANVAS", (char*)&canvas);

#if IM_VERSION_NUMBER > 312000
  double param[2] = { 0, 0 };
  if (!IupGetParam("Brightness and Contrast", brightcont_param_cb, dlg,
                   "Brightness Shift: %R[-100,100]\n"
                   "Contrast Factor: %R[-100,100]\n",
#else
  float param[2] = { 0, 0 };
  if (!IupGetParam("Brightness and Contrast", brightcont_param_cb, dlg,
                   "Brightness Shift: %r[-100,100]\n"
                   "Contrast Factor: %r[-100,100]\n",
#endif
                   &param[0], &param[1], NULL))
  {
    imImageDestroy(new_image);
    return IUP_DEFAULT;
  }

  /* since the image was already processed in preview we don't need to process it again,
     but leave it here to illustrate the logic */
  imProcessToneGamut(file.GetImage(), new_image, IM_GAMUT_BRIGHTCONT, param);

  UpdateImage(new_image);

  return IUP_DEFAULT;
}

int SimplePaint::ItemHelpActionCallback(Ihandle*)
{
  IupHelp("http://www.tecgraf.puc-rio.br/iup");
  return IUP_DEFAULT;
}

static int bt_ok_action_cb(Ihandle*)
{
  return IUP_CLOSE;
}

static int bt_sysinfo_action_cb(Ihandle*)
{
  IupVersionShow();
  return IUP_DEFAULT;
}

int SimplePaint::ItemAboutActionCallback(Ihandle* ih)
{
  Ihandle *bt_ok, *vbox, *dlg_about, *lbl, *bt_sysinfo, *txt;

  lbl = IupLabel(NULL);
  IupSetAttribute(lbl, "IMAGE", "SPLASH");

  bt_ok = IupButton("OK", NULL);
  IupSetAttribute(bt_ok, "PADDING", "6X3");
  IupSetCallback(bt_ok, "ACTION", bt_ok_action_cb);

  bt_sysinfo = IupButton("SysInfo", NULL);
  IupSetAttribute(bt_sysinfo, "PADDING", "6X3");
  IupSetCallback(bt_sysinfo, "ACTION", bt_sysinfo_action_cb);

  vbox = IupVbox(
    lbl,
    IupSetAttributes(IupLabel("Simple Paint 1.2"), "FONT=\"Helvetica, Bold 14\""),
    IupLabel("Copyright © 1995-2015 Tecgraf/PUC-Rio"),
    txt = IupSetAttributes(IupText(NULL), "READONLY=Yes, BORDER=NO, VALUE=\"iup@tecgraf.puc-rio.br\", VISIBLECOLUMNS=12, ALIGNMENT=ACENTER"),
    IupSetAttributes(IupLabel(NULL), "SEPARATOR=Horizontal"),
    IupSetAttributes(IupHbox(bt_sysinfo, IupFill(), bt_ok, NULL), "MARGIN=10x10"),
    NULL);

  IupSetAttribute(vbox, "ALIGNMENT", "ACENTER");
  IupSetAttribute(vbox, "MARGIN", "5x5");
  IupSetAttribute(vbox, "GAP", "5");
  IupSetAttribute(vbox, "FONT", "Helvetica, 12");

  dlg_about = IupDialog(vbox);
  IupSetAttribute(dlg_about, "TITLE", "About");
  IupSetAttribute(dlg_about, "RESIZE", "NO");
  IupSetAttribute(dlg_about, "MINBOX", "NO");
  IupSetAttribute(dlg_about, "MAXBOX", "NO");
  IupSetAttribute(dlg_about, "MENUBOX", "NO");
  IupSetAttributeHandle(dlg_about, "DEFAULTENTER", bt_ok);
  IupSetAttributeHandle(dlg_about, "DEFAULTESC", bt_ok);
  IupSetAttributeHandle(dlg_about, "PARENTDIALOG", IupGetDialog(ih));

  IupSetStrAttribute(txt, "BGCOLOR", IupGetAttribute(dlg_about, "BGCOLOR"));

  IupPopup(dlg_about, IUP_CENTERPARENT, IUP_CENTERPARENT);
  IupDestroy(dlg_about);
  return IUP_DEFAULT;
}


/********************************** Main *****************************************/


Ihandle* SimplePaint::CreateMainMenu()
{
  Ihandle *menu, *sub_menu_file;
  Ihandle *file_menu, *item_exit, *item_new, *item_open, *item_save, *item_saveas, *item_revert;
  Ihandle *sub_menu_edit, *edit_menu, *item_copy, *item_paste, *item_print, *item_pagesetup;
  Ihandle *sub_menu_help, *help_menu, *item_help, *item_about;
  Ihandle *sub_menu_view, *view_menu, *item_toolbar, *item_statusbar;
  Ihandle *item_zoomin, *item_zoomout, *item_actualsize;
  Ihandle *recent_menu, *item_background, *item_toolbox, *item_zoomgrid;
  Ihandle *sub_menu_image, *image_menu;

  item_new = IupItem("&New\tCtrl+N", NULL);
  IupSetAttribute(item_new, "IMAGE", "IUP_FileNew");
  IUP_CLASS_SETCALLBACK(item_new, "ACTION", ItemNewActionCallback);

  item_open = IupItem("&Open...\tCtrl+O", NULL);
  IupSetAttribute(item_open, "IMAGE", "IUP_FileOpen");
  IUP_CLASS_SETCALLBACK(item_open, "ACTION", ItemOpenActionCallback);

  item_save = IupItem("&Save\tCtrl+S", NULL);
  IupSetAttribute(item_save, "NAME", "ITEM_SAVE");
  IupSetAttribute(item_save, "IMAGE", "IUP_FileSave");
  IUP_CLASS_SETCALLBACK(item_save, "ACTION", ItemSaveActionCallback);

  item_saveas = IupItem("Save &As...", NULL);
  IupSetAttribute(item_saveas, "NAME", "ITEM_SAVEAS");
  IUP_CLASS_SETCALLBACK(item_saveas, "ACTION", ItemSaveasActionCallback);

  item_revert = IupItem("&Revert", NULL);
  IupSetAttribute(item_revert, "NAME", "ITEM_REVERT");
  IUP_CLASS_SETCALLBACK(item_revert, "ACTION", ItemRevertActionCallback);

  item_pagesetup = IupItem("Page Set&up...", NULL);
  IUP_CLASS_SETCALLBACK(item_pagesetup, "ACTION", ItemPagesetupActionCallback);

  item_print = IupItem("&Print...\tCtrl+P", NULL);
  IUP_CLASS_SETCALLBACK(item_print, "ACTION", ItemPrintActionCallback);

  item_exit = IupItem("E&xit", NULL);
  IUP_CLASS_SETCALLBACK(item_exit, "ACTION", ItemExitActionCallback);

  item_copy = IupItem("&Copy\tCtrl+C", NULL);
  IupSetAttribute(item_copy, "NAME", "ITEM_COPY");
  IupSetAttribute(item_copy, "IMAGE", "IUP_EditCopy");
  IUP_CLASS_SETCALLBACK(item_copy, "ACTION", ItemCopyActionCallback);

  item_paste = IupItem("&Paste\tCtrl+V", NULL);
  IupSetAttribute(item_paste, "NAME", "ITEM_PASTE");
  IupSetAttribute(item_paste, "IMAGE", "IUP_EditPaste");
  IUP_CLASS_SETCALLBACK(item_paste, "ACTION", ItemPasteActionCallback);

  item_zoomin = IupItem("Zoom &In\tCtrl++", NULL);
  IupSetAttribute(item_zoomin, "IMAGE", "IUP_ZoomIn");
  IUP_CLASS_SETCALLBACK(item_zoomin, "ACTION", ItemZoominActionCallback);

  item_zoomout = IupItem("Zoom &Out\tCtrl+-", NULL);
  IupSetAttribute(item_zoomout, "IMAGE", "IUP_ZoomOut");
  IUP_CLASS_SETCALLBACK(item_zoomout, "ACTION", ItemZoomoutActionCallback);

  item_actualsize = IupItem("&Actual Size\tCtrl+0", NULL);
  IupSetAttribute(item_actualsize, "IMAGE", "IUP_ZoomActualSize");
  IUP_CLASS_SETCALLBACK(item_actualsize, "ACTION", ItemActualsizeActionCallback);

  item_zoomgrid = IupItem("&Zoom Grid", NULL);
  IUP_CLASS_SETCALLBACK(item_zoomgrid, "ACTION", ItemZoomgridActionCallback);
  IupSetAttribute(item_zoomgrid, "NAME", "ITEM_ZOOMGRID");
  IupSetAttribute(item_zoomgrid, "VALUE", "ON");  /* default is ON */

  item_background = IupItem("&Background...", NULL);
  IUP_CLASS_SETCALLBACK(item_background, "ACTION", ItemBackgroundActionCallback);

  item_toolbar = IupItem("&Toobar", NULL);
  IUP_CLASS_SETCALLBACK(item_toolbar, "ACTION", ItemToolbarActionCallback);
  IupSetAttribute(item_toolbar, "NAME", "ITEM_TOOLBAR");
  IupSetAttribute(item_toolbar, "VALUE", "ON");   /* default is ON */

  item_toolbox = IupItem("&Toobox", NULL);
  IUP_CLASS_SETCALLBACK(item_toolbox, "ACTION", ItemToolboxActionCallback);
  IupSetAttribute(item_toolbox, "NAME", "ITEM_TOOLBOX");
  IupSetAttribute(item_toolbox, "VALUE", "ON");   /* default is ON */

  item_statusbar = IupItem("&Statusbar", NULL);
  IUP_CLASS_SETCALLBACK(item_statusbar, "ACTION", ItemStatusbarActionCallback);
  IupSetAttribute(item_statusbar, "NAME", "ITEM_STATUSBAR");
  IupSetAttribute(item_statusbar, "VALUE", "ON");  /* default is ON */

  item_help = IupItem("&Help...", NULL);
  IUP_CLASS_SETCALLBACK(item_help, "ACTION", ItemHelpActionCallback);

  item_about = IupItem("&About...", NULL);
  IUP_CLASS_SETCALLBACK(item_about, "ACTION", ItemAboutActionCallback);

  recent_menu = IupMenu(NULL);

  file_menu = IupMenu(
    item_new,
    item_open,
    item_save,
    item_saveas,
    item_revert,
    IupSeparator(),
    item_pagesetup,
    item_print,
    IupSeparator(),
    IupSubmenu("Recent &Files", recent_menu),
    IupSeparator(),
    item_exit,
    NULL);
  edit_menu = IupMenu(
    item_copy,
    item_paste,
    NULL);
  view_menu = IupMenu(
    item_zoomin,
    item_zoomout,
    item_actualsize,
    item_zoomgrid,
    IupSeparator(),
    item_background,
    IupSeparator(),
    item_toolbar,
    item_toolbox,
    item_statusbar,
    NULL);
  image_menu = IupMenu(
    IupSetCallbacks(IupItem("&Resize...", NULL), "ACTION", CB_ItemResizeActionCallback, NULL),
    IupSetCallbacks(IupItem("&Mirror", NULL), "ACTION", CB_ItemMirrorActionCallback, NULL),
    IupSetCallbacks(IupItem("&Flip", NULL), "ACTION", CB_ItemFlipActionCallback, NULL),
    IupSetCallbacks(IupItem("&Rotate 180º", NULL), "ACTION", CB_ItemRotate180ActionCallback, NULL),
    IupSetCallbacks(IupItem("&Rotate +90º (clock-wise)", NULL), "ACTION", CB_ItemRotate90cwActionCallback, NULL),
    IupSetCallbacks(IupItem("&Rotate -90º (counter-clock)", NULL), "ACTION", CB_ItemRotate90ccwActionCallback, NULL),
    IupSeparator(),
    IupSetCallbacks(IupItem("&Negative", NULL), "ACTION", CB_ItemNegativeActionCallback, NULL),
    IupSetCallbacks(IupItem("&Brightness and Contrast...", NULL), "ACTION", CB_ItemBrightcontActionCallback, NULL),
    NULL);
  help_menu = IupMenu(
    item_help,
    item_about,
    NULL);
  
  IUP_CLASS_SETCALLBACK(file_menu, "OPEN_CB", FileMenuOpenCallback);
  IUP_CLASS_SETCALLBACK(edit_menu, "OPEN_CB", EditMenuOpenCallback);
  IUP_CLASS_SETCALLBACK(view_menu, "OPEN_CB", ViewMenuOpenCallback);

  sub_menu_file = IupSubmenu("&File", file_menu);
  sub_menu_edit = IupSubmenu("&Edit", edit_menu);
  sub_menu_view = IupSubmenu("&View", view_menu);
  sub_menu_image = IupSubmenu("&Image", image_menu);
  sub_menu_help = IupSubmenu("&Help", help_menu);

  menu = IupMenu(
    sub_menu_file,
    sub_menu_edit,
    sub_menu_view,
    sub_menu_image,
    sub_menu_help,
    NULL);

  IupConfigRecentInit(config, recent_menu, CB_ConfigRecentCallback, 10);

  return menu;
}

Ihandle* SimplePaint::CreateToolbar()
{
  Ihandle *toolbar;
  Ihandle *btn_copy, *btn_paste, *btn_new, *btn_open, *btn_save, *btn_zoomgrid;

  IupSetHandle("PaintZoomGrid", load_image_PaintZoomGrid());

  btn_new = IupButton(NULL, NULL);
  IupSetAttribute(btn_new, "IMAGE", "IUP_FileNew");
  IupSetAttribute(btn_new, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_new, "ACTION", ItemNewActionCallback);
  IupSetAttribute(btn_new, "TIP", "New (Ctrl+N)");
  IupSetAttribute(btn_new, "CANFOCUS", "No");

  btn_open = IupButton(NULL, NULL);
  IupSetAttribute(btn_open, "IMAGE", "IUP_FileOpen");
  IupSetAttribute(btn_open, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_open, "ACTION", ItemOpenActionCallback);
  IupSetAttribute(btn_open, "TIP", "Open (Ctrl+O)");
  IupSetAttribute(btn_open, "CANFOCUS", "No");

  btn_save = IupButton(NULL, NULL);
  IupSetAttribute(btn_save, "IMAGE", "IUP_FileSave");
  IupSetAttribute(btn_save, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_save, "ACTION", ItemSaveActionCallback);
  IupSetAttribute(btn_save, "TIP", "Save (Ctrl+S)");
  IupSetAttribute(btn_save, "CANFOCUS", "No");

  btn_copy = IupButton(NULL, NULL);
  IupSetAttribute(btn_copy, "IMAGE", "IUP_EditCopy");
  IupSetAttribute(btn_copy, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_copy, "ACTION", ItemCopyActionCallback);
  IupSetAttribute(btn_copy, "TIP", "Copy (Ctrl+C)");
  IupSetAttribute(btn_copy, "CANFOCUS", "No");

  btn_paste = IupButton(NULL, NULL);
  IupSetAttribute(btn_paste, "IMAGE", "IUP_EditPaste");
  IupSetAttribute(btn_paste, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_paste, "ACTION", ItemPasteActionCallback);
  IupSetAttribute(btn_paste, "TIP", "Paste (Ctrl+V)");
  IupSetAttribute(btn_paste, "CANFOCUS", "No");

  btn_zoomgrid = IupButton(NULL, NULL);
  IupSetAttribute(btn_zoomgrid, "IMAGE", "PaintZoomGrid");
  IupSetAttribute(btn_zoomgrid, "FLAT", "Yes");
  IUP_CLASS_SETCALLBACK(btn_zoomgrid, "ACTION", ItemZoomgridActionCallback);
  IupSetAttribute(btn_zoomgrid, "TIP", "Zoom Grid");
  IupSetAttribute(btn_zoomgrid, "CANFOCUS", "No");

  toolbar = IupHbox(
    btn_new,
    btn_open,
    btn_save,
    IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
    btn_copy,
    btn_paste,
    IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
    btn_zoomgrid,
    NULL);
  IupSetAttribute(toolbar, "MARGIN", "5x5");
  IupSetAttribute(toolbar, "GAP", "2");
  IupSetAttribute(toolbar, "NAME", "TOOLBAR");

  /* Initialize variables from the configuration file */

  if (!IupConfigGetVariableIntDef(config, "MainWindow", "Toolbar", 1))
  {
    IupSetAttribute(toolbar, "FLOATING", "YES");
    IupSetAttribute(toolbar, "VISIBLE", "NO");
  }

  return toolbar;
}

Ihandle* SimplePaint::CreateStatusbar()
{
  Ihandle *statusbar;

  statusbar = IupHbox(
    IupSetAttributes(IupLabel("(0, 0) = 0   0   0"), "EXPAND=HORIZONTAL, PADDING=10x5, NAME=STATUSLABEL"),
    IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
    IupSetAttributes(IupLabel("0 x 0"), "SIZE=70x, PADDING=10x5, NAME=SIZELABEL, ALIGNMENT=ACENTER"),
    IupSetAttributes(IupLabel(NULL), "SEPARATOR=VERTICAL"),
    IupSetAttributes(IupLabel("100%"), "SIZE=30x, PADDING=10x5, NAME=ZOOMLABEL, ALIGNMENT=ARIGHT"),
    IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomOut, FLAT=Yes, TIP=\"Zoom Out (Ctrl+-)\", CANFOCUS=No"), "ACTION", CB_ItemZoomoutActionCallback, NULL),
    IupSetCallbacks(IupSetAttributes(IupVal(NULL), "VALUE=0, MIN=-6, MAX=6, SIZE=50x10, NAME=ZOOMVAL, CANFOCUS=No"), "VALUECHANGED_CB", CB_ZoomValueChangedCallback, NULL),
    IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomIn, FLAT=Yes, TIP=\"Zoom In (Ctrl++)\", CANFOCUS=No"), "ACTION", CB_ItemZoominActionCallback, NULL),
    IupSetCallbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=IUP_ZoomActualSize, FLAT=Yes, TIP=\"Actual Size (Ctrl+0)\", CANFOCUS=No"), "ACTION", CB_ItemActualsizeActionCallback, NULL),
    NULL);
  IupSetAttribute(statusbar, "NAME", "STATUSBAR");
  IupSetAttribute(statusbar, "ALIGNMENT", "ACENTER");

  /* Initialize variables from the configuration file */

  if (!IupConfigGetVariableIntDef(config, "MainWindow", "Statusbar", 1))
  {
    IupSetAttribute(statusbar, "FLOATING", "YES");
    IupSetAttribute(statusbar, "VISIBLE", "NO");
  }

  return statusbar;
}

void SimplePaint::CreateMainDialog(Ihandle* iup_canvas)
{
  Ihandle *vbox;

  vbox = IupVbox(
    CreateToolbar(),
    iup_canvas,
    CreateStatusbar(),
    NULL);

  dlg = IupDialog(vbox);
  IupSetAttributeHandle(dlg, "MENU", CreateMainMenu());
  IupSetAttribute(dlg, "SIZE", "HALFxHALF");
  IUP_CLASS_SETCALLBACK(dlg, "CLOSE_CB", ItemExitActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "DROPFILES_CB", DialogDropfilesCallback);
  IUP_CLASS_SETCALLBACK(dlg, "MOVE_CB", DialogMoveCallback);

  IUP_CLASS_SETCALLBACK(dlg, "K_cN", ItemNewActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cO", ItemOpenActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cS", ItemSaveActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cV", ItemPasteActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cC", ItemCopyActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cP", ItemPrintActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cMinus", ItemZoomoutActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cPlus", ItemZoominActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_cEqual", ItemZoominActionCallback);
  IUP_CLASS_SETCALLBACK(dlg, "K_c0", ItemActualsizeActionCallback);

  /* parent for pre-defined dialogs in closed functions (IupMessage and IupAlarm) */
  IupSetAttributeHandle(NULL, "PARENTDIALOG", dlg);
}

SimplePaint::SimplePaint()
  :dlg(NULL), config(NULL), file(), toolbox(), canvas()
{

  /***************  Config ***********/
  config = IupConfig();
  IupSetAttribute(config, "APP_NAME", "simple_paint");
  IupConfigLoad(config);


  /***************  Canvas ***********/
  Ihandle* iup_canvas = canvas.CreateCanvas(&file, &toolbox);

  /* Initialize variables from the configuration file */
  const char* background_str = IupConfigGetVariableStr(config, "Canvas", "Background");
  if (background_str)
  {
    unsigned int ri, gi, bi;
    sscanf(background_str, "%u %u %u", &ri, &gi, &bi);
    canvas.SetBackground(cdEncodeColor((unsigned char)ri, (unsigned char)gi, (unsigned char)bi));
  }

  if (!IupConfigGetVariableIntDef(config, "Canvas", "ZoomGrid", 1))
    canvas.SetZoomGrid(false);


  /***************  Dialog ***********/
  CreateMainDialog(iup_canvas);

  IUP_CLASS_INITCALLBACK(dlg, SimplePaint);

  /* show the dialog at the last position, with the last size */
  IupConfigDialogShow(config, dlg, "MainWindow");


  /***************  Toolbox ***********/
  toolbox.CreateDialog(dlg, config);

  /* Initialize variables from the configuration file */
  if (IupConfigGetVariableIntDef(config, "MainWindow", "Toolbox", 1))
  {
    /* configure the very first time to be aligned with the canvas top left corner */
    if (!IupConfigGetVariableStr(config, "Toolbox", "X"))
    {
      int x = IupGetInt(iup_canvas, "X");
      int y = IupGetInt(iup_canvas, "Y");
      IupConfigSetVariableInt(config, "Toolbox", "X", x);
      IupConfigSetVariableInt(config, "Toolbox", "Y", y);
    }

    toolbox.ShowDialog();
  }
}
