jLife : a new version of the game of Life (Conway) that uses win32 SDK and genetics

Download jlife.zip

Synopsis:

Makefile
main.cpp
Animal.cpp
Animal.h
App.cpp
App.h
CalcThread.cpp
CalcThread.h
Cell.cpp
Cell.h
CLArguments.cpp
CLArguments.h
EnvironmentInfo.h
Grid.cpp
Grid.h
GridInfo.h
Help.cpp
Help.h
jBaseThread.cpp
jBaseThread.h
jCanvas.h
jColor.h
jComponentList.h
jDialog.cpp
jDialog.h
jFrameWin.cpp
jFrameWin.h
jFunctor.h
jGDIResourceLeak.cpp
jGDIResourceLeak.h
jGraphics.cpp
jGraphics.h
jICallBack.h
jListBox.cpp
jListBox.h
jMenu.cpp
jMenu.h
jNativeWin.cpp
jNativeWin.h
jRect.h
jTypeList.h
jWin.h
jWinComponent.h


Makefile

Synopsis
srcdir = .
builddir = /cygdrive/d/projects/debug/jlife

#ressrc1 = Generic.rc
#ressrc = $(addprefix $(srcdir)/,$(ressrc1))
#
#resobj1 = $(subst .rc,.o,$(ressrc1))
#resobj = $(addprefix $(builddir)/,$(resobj1))

src1 =  $(wildcard *.cpp)
src = $(addprefix $(srcdir)/,$(src1))

objs1 = $(subst .cpp,.o,$(src1))
objs = $(addprefix $(builddir)/,$(objs1))

deps1 = $(subst .cpp,.d,$(src1))
deps = $(addprefix $(builddir)/,$(deps1))

exec = jlife.exe

incl-dirs = -I d:/projects/include

#---------------
#-- tools
RESCOMP = windres
CXX = g++

#---------------
#-- compiler switches
#CPPFLAGS = -mno-cygwin -mwindows -g
CPPFLAGS = -mno-cygwin  -g -Wall -MD

#---------------
#-- MS libs required
#LIBS_MS =  -lrpcrt4 -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -lctl3d32 -ladvapi32  -lkernel32 -luser32
LIBS_MS = -lgdi32

#---------------
#-- final set of libs
LIBS = $(LIBS_MS)

#---------------
#-- linker switches
# -s : strip debug info
LDFLAGS = -mwindows -mno-cygwin 

#---------------
#-- RC COMPILER SWITCHES
#RC_INCLUDES = --include-dir $(srcdir) --include-dir $(WX_INCLUDE)
#RC_FLAGS = --define __WXMSW__ $(RC_INCLUDES) $(DLLFLAG_rc)
RC_INCLUDES = 
RC_FLAGS =

#----------------------------------------------------------------------------------------
#-- Main dependencies!

.PHONY: all clean

all: $(builddir) $(exec)

#---------------
#-- Target: executable
$(exec) : $(objs)
	$(info ---Linking...) 
	g++  $(LDFLAGS) $^ $(LIBS) -o $@

#---------------
#-- Target: clean
clean :
	-rm -rf $(builddir)
	-rm *.o
	-rm *.d
	-rm *.exe

#-- build dir
$(builddir) :
	$(info ---Creating build directory...) 
	if [ ! -d $(builddir) ]; then mkdir -p $(builddir); fi

include $(wildcard $(builddir)/*.d)

#-- source files	
$(objs): $(builddir)/%.o:$(srcdir)/%.cpp 
	$(info ---Build source file...) 
	g++ $(incl-dirs) -c $(CPPFLAGS) $(srcdir)/$< -o $@

#-- resource file
$(resobj) : $(builddir)/%.o:$(srcdir)/%.rc
	$(info ---Build resource file...) 
	$(RESCOMP) -i$< -o$@ $(RC_FLAGS)

 

main.cpp

Synopsis
#include "App.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>

int main(int argc, char** argv)
  {
  srand(time(0));
  App app(std::cout);
  app.Run(argc, argv);
  return app.ReturnCode();
  }

Animal.cpp

Synopsis
#include "Animal.h"
#include "jColor.h"
#include "EnvironmentInfo.h"
#include <stdlib.h>

static jColor WHITE(255, 255, 255);
static jColor ANIMAL1_2(16, 78, 139);
static jColor ANIMAL1_1(28, 134, 238);
static jColor ANIMAL1_0(165, 210, 245);
static jColor ANIMAL1_BABY(187, 255, 255);

//the master from which all Animals are copied... unless there's genetic crossover and mutation.
Animal gMasterAnimal;

Animal::Animal()
  {
  Init();
  }

void Animal::Init()
  {
  Type = 0;
  Energy = 0;
  Age = 0;
  YoungThreshold = 50; //this age and below is "young"
  OldThreshold = 200; //this age and above is "old"
  EnergyLossPerDay = 2; //the amount of energy Animal1 loses per day
  PercentageEnergyLossYoung = 0.00010; //additional energy loss due to youth
  PercentageEnergyLossOld = 0.00260; //additional energy loss due to old age
  PlantsEatenPerDay = 6; //the amount of plants Animal1 eats
  EnergyGainedByEatingPlants = 4; //the amount of energy Animal1 gets by eating plants
  ExistsPercentage = 50; //the percentage of time an Animal1 is initially created
  EnergyToMove = 6; //the amount of energy to move closer to food
  ParentEnergyThreshold = 150; //how much energy Animal1 needs to be a parent
  ChildMinimumEnergy = 50; //the minimum amount of energy Animal1 children get when they are born
  ChildPercentageAdditionalEnergy = 0.15; //additional energy they get from the parents.

  //set this to 100 to show that socialable is anti-survival!
  //set this to 0 to show a voracious, eating machine.
  Sociability = 0; //on sociable the animal is 0..100, 0 is unsociable, 100 is "clingy"
  }

Animal& Animal::operator=(const Animal& other)
  {
  Type = other.Type;
  Energy = other.Energy;
  Age = other.Age;
  YoungThreshold = other.YoungThreshold;
  OldThreshold = other.OldThreshold; //this age and above is "old"
  EnergyLossPerDay = other.EnergyLossPerDay; //the amount of energy Animal1 loses per day
  PercentageEnergyLossYoung = other.PercentageEnergyLossYoung; //additional energy loss due to youth
  PercentageEnergyLossOld = other.PercentageEnergyLossOld; //additional energy loss due to old age
  PlantsEatenPerDay = other.PlantsEatenPerDay; //the amount of plants Animal1 eats
  EnergyGainedByEatingPlants = other.EnergyGainedByEatingPlants; //the amount of energy Animal1 gets by eating plants
  ExistsPercentage = other.ExistsPercentage; //the percentage of time an Animal1 is initially created
  EnergyToMove = other.EnergyToMove; //the amount of energy it costs to move an Animal1
  ParentEnergyThreshold = other.ParentEnergyThreshold; //how much energy Animal1 needs to be a parent
  ChildMinimumEnergy = other.ChildMinimumEnergy; //the minimum amount of energy Animal1 children get when they are born
  ChildPercentageAdditionalEnergy = other.ChildPercentageAdditionalEnergy; //additional energy they get from the parents.
  Sociability = other.Sociability;
  return *this;
  }

void Animal::SetInitial(const Animal& master)
  {
  this->operator =(master);
  int exists = rand() % 100;
  if (exists < ExistsPercentage)
    {
    Energy = (rand() % 100) + 1;
    Age = (rand() % 600) + 1;
    Type = 1;
    }
  }

bool Animal::Exists() const
  {
  return Energy > 0;
  }

void Animal::KillIt()
  {
  Type = 0;
  Energy = 0;
  Age = 0;
  }

void Animal::Update(int& currentPlantLife)
  {
  //animal ages every day
  Age++;

  if (currentPlantLife >= PlantsEatenPerDay)
    {
    //there are enough plants to eat...
    currentPlantLife -= PlantsEatenPerDay;
    Energy += EnergyGainedByEatingPlants;
    }

  //animal loses energy every day
  Energy -= EnergyLossPerDay;

  //young animals lose more energy
  if (Age < YoungThreshold)
    {
    //lose more energy the younger you are...
    Energy -= (int) ((YoungThreshold - Age) * Energy * PercentageEnergyLossYoung);
    }

  //old animals lose more energy
  if (Age > OldThreshold)
    {
    //lose more energy the older you are...
    Energy -= (int) ((Age - OldThreshold) * Energy * PercentageEnergyLossOld);
    }

  //if the animal has no energy, it's dead
  if (!Exists())
    {
    KillIt();
    }
  }

jColor Animal::GetColor() const
  {
  if (Age < 10)
    return ANIMAL1_BABY;

  if (Energy > 66)
    return ANIMAL1_2;

  if (Energy > 33)
    return ANIMAL1_1;

  if (Energy > 0)
    return ANIMAL1_0;

  //it's dead
  return WHITE;
  }

//if occupied
bool Animal::IsHigherThenSet(int& energy)
  {
  if (Energy > energy)
    {
    energy = Energy;
    return true;
    }
  return false;
  }

bool Animal::IsSociable() const
  {
  int dice = rand() % 100;
  return (Sociability > dice) && (Energy >= EnergyToMove);
  }

//move if: not enough plantlife and there's enough energy to move
bool Animal::NotEnoughFood(int currentPlantLife) const
  {
  return (currentPlantLife < PlantsEatenPerDay) && (Energy >= EnergyToMove);
  }

void Animal::Move(Animal& from)
  {
  if (from.Energy < from.EnergyToMove)
    return; //not enough energy to move

  //a move is a copy from the original spot...
  this->operator =(from);

  //remove a bit of energy...
  Energy -= EnergyToMove;
  if (!Exists())
    KillIt();

  //and remove it from the previous cell
  from.KillIt();
  }

//both parents have to have enough energy to have a child
bool Animal::CanBeBorn(int parent1energy, int parent2energy) const
  {
  bool b = parent1energy >= ParentEnergyThreshold && parent2energy >= ParentEnergyThreshold;
  //std::cout << "CanBeBorn: " << b << std::endl;
  return b;
  }

bool changeit(int& item)
  {
  int dice = rand() % 100;
  if (dice > 98)
    {
    item++;
    return true;
    }
  if (dice < 2)
    {
    item--;
    return true;
    }
  return false;
  }

bool changeit(double& item)
  {
  int dice = rand() % 100;
  if (dice > 98)
    {
    item += 0.0001;
    return true;
    }
  if (dice < 2)
    {
    item -= 0.0001;
    return true;
    }
  return false;
  }

//   - the child's energy is a minimum value + a random extra value, depending on parent's energy
void Animal::BeBorn(const Animal& parent1, const Animal& parent2)
  {
  if (!gEnvironment.UseGenetics)
    {
    //copy current settings from master animal
    this->operator=(gMasterAnimal);
    }

  //arbitrarily choose parent1 here
  //if genetics are in use, it will be overwritten
  //otherwise, both parents have the same type anyway
  Type = parent1.Type;

  //max energy the child gets is a percentage from each of the parents
  double max = ChildPercentageAdditionalEnergy * parent1.Energy;
  max += ChildPercentageAdditionalEnergy * parent2.Energy;
  Energy = ChildMinimumEnergy;
  Energy += rand() % (int) max; //ranges from 0..max

  //we all start so young...
  Age = 1;

  //since the animal has energy and a non-zero age,
  //   it is officially born at this point

  if (gEnvironment.UseGenetics)
    {
    //handle crossover from either parents items
    Crossover(parent1, parent2);

    //handle mutations
    Mutate(parent1, parent2);
    }
  }

// the child's energy will be subtracted from each of the parents
void Animal::AdjustParentForBirthOf(const Animal& child)
  {
  //there is no female and male, so each gives up their energy equally 
  Energy -= child.Energy / 2;
  if (!Exists())
    KillIt(); //died in childbirth
  }

void Animal::Crossover(const Animal& parent1, const Animal& parent2)
  {
  int dice;
  dice = rand() % 100;
  YoungThreshold = dice > 50 ? parent1.YoungThreshold : parent2.YoungThreshold;
  dice = rand() % 100;
  OldThreshold = dice > 50 ? parent1.OldThreshold : parent2.OldThreshold;
  dice = rand() % 100;
  EnergyLossPerDay = dice > 50 ? parent1.EnergyLossPerDay : parent2.EnergyLossPerDay;
  dice = rand() % 100;
  PercentageEnergyLossYoung = dice > 50 ? parent1.PercentageEnergyLossYoung
                                        : parent2.PercentageEnergyLossYoung;
  dice = rand() % 100;
  PercentageEnergyLossOld = dice > 50 ? parent1.PercentageEnergyLossOld
                                      : parent2.PercentageEnergyLossOld;
  dice = rand() % 100;
  PlantsEatenPerDay = dice > 50 ? parent1.PlantsEatenPerDay : parent2.PlantsEatenPerDay;
  dice = rand() % 100;
  EnergyGainedByEatingPlants = dice > 50 ? parent1.EnergyGainedByEatingPlants
                                         : parent2.EnergyGainedByEatingPlants;
  dice = rand() % 100;
  ExistsPercentage = dice > 50 ? parent1.ExistsPercentage : parent2.ExistsPercentage;
  dice = rand() % 100;
  EnergyToMove = dice > 50 ? parent1.EnergyToMove : parent2.EnergyToMove;
  dice = rand() % 100;
  ParentEnergyThreshold = dice > 50 ? parent1.ParentEnergyThreshold : parent2.ParentEnergyThreshold;
  dice = rand() % 100;
  ChildMinimumEnergy = dice > 50 ? parent1.ChildMinimumEnergy : parent2.ChildMinimumEnergy;
  dice = rand() % 100;
  ChildPercentageAdditionalEnergy = dice > 50 ? parent1.ChildPercentageAdditionalEnergy
                                              : parent2.ChildPercentageAdditionalEnergy;
  }

void Animal::Mutate(const Animal& parent1, const Animal& parent2)
  {
  bool mutation = false;

  mutation |= changeit(YoungThreshold);
  mutation |= changeit(OldThreshold);
  mutation |= changeit(EnergyLossPerDay);
  mutation |= changeit(PercentageEnergyLossYoung);
  mutation |= changeit(PercentageEnergyLossOld);
  mutation |= changeit(PlantsEatenPerDay);
  mutation |= changeit(EnergyGainedByEatingPlants);
  //ExistsPercentage
  mutation |= changeit(EnergyToMove);
  mutation |= changeit(ParentEnergyThreshold);
  mutation |= changeit(ChildMinimumEnergy);
  mutation |= changeit(ChildPercentageAdditionalEnergy);

  if (mutation)
    {
    Type = parent1.Type + 1;
    }
  else
    {
    Type = parent1.Type; //todo: use Parent's type
    }
  }

Animal.h

Synopsis
#ifndef ANIMAL_H_
#define ANIMAL_H_

#include "jColor.h"

class Animal
  {
  public:
    Animal();

    inline int GetType()
      {
      return Type;
      }
    void Init();
    void SetInitial(const Animal& master);
    void Update(int& currentPlantLife);
    bool CanBeBorn(int parent1energy, int parent2energy) const;
    bool Exists() const;
    jColor Animal::GetColor() const;
    bool IsHigherThenSet(int& energy);
    bool NotEnoughFood(int currentPlantLife) const;
    void Move(Animal& from);
    bool IsSociable() const;
    void BeBorn(const Animal& parent1, const Animal& parent2);
    void AdjustParentForBirthOf(const Animal& child);
    Animal& operator=(const Animal& other);

  private:
    void KillIt();
    void Crossover(const Animal& parent1, const Animal& parent2);
    void Mutate(const Animal& parent1, const Animal& parent2);

    int Type;
    int Energy;
    int Age;
public:
    int EnergyToMove;
    int PlantsEatenPerDay;
    int EnergyGainedByEatingPlants;
    int EnergyLossPerDay;
    int ExistsPercentage;
    int YoungThreshold;
    int OldThreshold;
    double PercentageEnergyLossYoung;
    double PercentageEnergyLossOld;
    int ParentEnergyThreshold;
    int ChildMinimumEnergy;
    double ChildPercentageAdditionalEnergy;
    int Sociability;
  };

extern Animal gMasterAnimal;
#endif /*ANIMALINFO_H_*/

App.cpp

Synopsis
#include "App.h"
#include "jFunctor.h"
#include "Grid.h"
#include "GridInfo.h"
#include "EnvironmentInfo.h"
#include "jRect.h"
#include "jDialog.h"
//#include "jGDIResourceLeak.h"

#include <string>
#include <iostream>

static const int cRc_OK = 0;
static const int cRc_BadArgument = 1;
static const int cRc_CompareFailed = 2;

static Grid grid;

App::App(std::ostream& os) :
  mOstream(os)
  {
  mStopProcessing = false;
  mRc = cRc_OK;
  mGeneration = 0;
  }

App::~App(void)
  {
  }

int App::ReturnCode()
  {
  return mRc;
  }

int App::OnMenuExit(const std::string& name)
  {
  std::cout << "OnMenuExit name=" << name << std::endl;
  mWin.Close();
  return 0;
  }

//int App::OnMenuSave(const std::string& name)
//  {
//  std::cout << "OnMenuSave name=" << name << std::endl;
//  return 0;
//  }

int App::OnSettingsDone(const std::string& name)
  {
  std::cout << "OnSettingsDone name=" << name << std::endl;
  if (name == "Ok")
  	{
    mDlg.Close(0);
    mWin.Redraw(); //redraw the screen 
    }
  else if (name == "Cancel")
  	{
    mDlg.Close(1);
    }
  mWin.SetActive();  
  return 0;
  }

int App::OnMenuSettings(const std::string& name)
  {
  std::cout << "OnMenuSettings name=" << name << std::endl;
  //todo: do settings dialog
  jRect rct;
  rct.x = 100;
  rct.y = 100;
  rct.width = 200;
  rct.height = 150;
  mDlg.Create(mWin.getWin(), "jLife - Settings...", rct);

  EnvironmentInfo tmpenv = gEnvironment;
  Animal tmpanimal = gMasterAnimal;

  //                 label       field,                x,    y, lblw, entrywidth, height
  int gap = 5;
  int lblx = gap + gap;
  int lblwidth = 90;
  int editwidth = 20;
  int height = 10;
  int y = 10;
  mDlg.AddLabel("Sunshine%", lblx, y, lblwidth, height);
  mDlg.AddEdit(tmpenv.SunPercentage, tmpenv.SunPercentage, lblx + lblwidth + gap, y, editwidth, height);

  y += height + gap;
  mDlg.AddLabel("Plant Life w/ Dirt", lblx, y, lblwidth, height);
    mDlg.AddEdit(tmpenv.PlantLifeIncWithDirt, tmpenv.PlantLifeIncWithDirt, lblx + lblwidth + gap, y, editwidth, height);

  y += height + gap;
  mDlg.AddLabel("Plant Life w/out Dirt", lblx, y, lblwidth, height);
  mDlg.AddEdit(tmpenv.PlantLifeIncWithoutDirt, tmpenv.PlantLifeIncWithoutDirt, lblx + lblwidth + gap, y, editwidth, height);

  y += height + gap;
  mDlg.AddLabel("Plant Life w/out Sun", lblx, y, lblwidth, height);
  mDlg.AddEdit(tmpenv.PlantLifeDecWithoutSunshine, tmpenv.PlantLifeDecWithoutSunshine, lblx + lblwidth + gap, y, editwidth, height);

  y += height + gap;
  mDlg.AddLabel("Use Genetics", lblx, y, lblwidth, height);
  mDlg.AddEdit((int)tmpenv.UseGenetics, (int&) tmpenv.UseGenetics, lblx + lblwidth + gap, y, editwidth, height);

  y += height + gap;
  mDlg.AddLabel("Sociability", lblx, y, lblwidth, height);
  mDlg.AddEdit(tmpanimal.Sociability, tmpanimal.Sociability, lblx + lblwidth + gap, y, editwidth, height);

  DialogCallBack cmd(this, &App::OnSettingsDone);

  int buttonwidth = 40;
//  y += height + gap;
//  mDlg.AddButton("Help", cmd, lblx, y, buttonwidth, height);
  y += height + gap;
  mDlg.AddButton("Ok", cmd, lblx, y, buttonwidth, height);
  mDlg.AddButton("Cancel", cmd, lblx + buttonwidth + gap, y, buttonwidth, height);

  unsigned long rc = mDlg.Show(); //defaults Modal

  //std::cout << "x=App tmp=" << tmp << " tmp2=" << tmp2 << std::endl;
  if (rc == 0)
    {
    gEnvironment = tmpenv;
    gMasterAnimal = tmpanimal;
    }

  return 0;
  }

int App::OnMenuReInit(const std::string& name)
  {
  std::cout << "OnMenuReInit name=" << name << std::endl;
  grid.ReInit();
  mWin.Redraw();
  return 0;
  }

int App::OnMenuGoStop(const std::string& name)
  {
  std::cout << "OnMenuGoStop name=" << name << std::endl;

  if (name == "Go!")
    {
    mSettingId->SetEnabled(false);
    mWin.PostEvent(1, 22, 33);
    mGoStopId->SetMenuItemText("Stop!");
    mCalcThread->Unfreeze();
    }
  else
    {
    mSettingId->SetEnabled(true);
    mGoStopId->SetMenuItemText("Go!");
    mWin.PostEvent(1, 0, 0);
    mCalcThread->Freeze();
    }

  return 0;
  }

enum
  {
  MYEVENT = 42
  };
int App::OnMyEvent(unsigned int p1)
  {
  //std::cout << "OnMyEvent p1=" << p1 << std::endl;
  mGeneration++;
  mWin.Redraw();
  return 0;
  }

int App::OnPaint(jGraphics& g)
  {
  grid.Paint(g, mGeneration);
  return 0;
  }

void App::Run(int argc, char** argv)
  {
  ProcessCommandLine(argc, argv);
  if (mStopProcessing)
    return;

  grid.Init();

  mWin.Create();
  mWin.Text("jLife - new game of Life");

  //create menu system
  jMenu mMenu = mWin.AddMenu();
  mMenu.CreateDropDown("File");
  //  MenuCallBack cmd1(this, &App::OnMenuSave);
  //  mMenu.AddItem("Save", cmd1);
  MenuCallBack cmd2(this, &App::OnMenuExit);
  mMenu.AddItem("Exit", cmd2);

  MenuCallBack settingscmd(this, &App::OnMenuSettings);
  mSettingId = mMenu.CreateMenuItem("Settings...", settingscmd);

  MenuCallBack reinitcmd(this, &App::OnMenuReInit);
  mMenu.CreateMenuItem("Re-Init!", reinitcmd);

  MenuCallBack gostopcmd(this, &App::OnMenuGoStop);
  mGoStopId = mMenu.CreateMenuItem("Go!", gostopcmd);

  PaintCallBack pcmd(this, &App::OnPaint);
  mWin.AddOnPaintCallBack(pcmd);

  GenericCallBack gcmd(this, &App::OnMyEvent);
  mWin.AddGenericCallBack(MYEVENT, gcmd);

  mCalcThread = new CalcThread(mWin, MYEVENT, grid);
  mCalcThread->Freeze();
  mCalcThread->Start();

  mWin.SetSize((GridInfo::colwidth * GridInfo::numcols) + 250, (GridInfo::rowheight
      * GridInfo::numrows) + 250);

  mOstream << "about to show " << std::endl;
  mRc = mWin.Show();
  }

void App::ProcessCommandLine(int argc, char** argv)
  {
  try
    {
    for (int i = 1; i < argc; i++)
      mArgs.ProcessArg(argv[i]);
    }
  catch (std::string& err)
    {
    mStopProcessing = true;
    if (err == "help")
      {
      mRc = cRc_OK;
      }
    else
      {
      mOstream << err << std::endl;
      mRc = cRc_BadArgument;
      }
    }

  if (mStopProcessing || !mArgs.IsValid())
    {
    mHelp.printOn(mOstream);
    mRc = cRc_BadArgument;
    }
  }

App.h

Synopsis
#pragma once
#include "jFrameWin.h"
#include "jDialog.h"
#include "Help.h"
#include "CLArguments.h"
#include "jGraphics.h"
#include "CalcThread.h"
#include <ostream>

class App
  {
  public:
    explicit App(std::ostream& os);
    ~App(void);
    void Run(int argc, char** argv);
    int ReturnCode();

  protected:
    void ProcessCommandLine(int argc, char** argv);

    //int OnMenuCompare(const std::string& name);
    int OnMenuExit(const std::string& name);
    //int OnMenuSave(const std::string& name);
    //int OnMenuUp(const std::string& name);
    //int OnMenuDown(const std::string& name);
    int OnMenuSettings(const std::string& name);
    int OnSettingsDone(const std::string& name);
    int OnMenuReInit(const std::string& name);
    int OnMenuGoStop(const std::string& name);
    int OnMyEvent(unsigned int p1);
    int OnPaint(jGraphics& g);

  private:
    friend class Test;
    std::ostream& mOstream;
    Help mHelp;
    int mRc;
    bool mStopProcessing;
    CLArguments mArgs;
    CalcThread* mCalcThread;
    jFrameWin mWin;
    jDialog mDlg;
    jMenu::MenuItem* mGoStopId;
    jMenu::MenuItem* mSettingId;
    int mGeneration;
  };

CalcThread.cpp

Synopsis
#include "CalcThread.h"
#include "jFrameWin.h"
#include "Grid.h"
#include <wtypes.h>
#include <time.h>
#include <iostream>

//--------------------
CalcThread::CalcThread(jFrameWin& w, unsigned short callbackid, Grid& g) :
  mWin(w), mGrid(g), mCallBackId(callbackid), mDone(false), mFrozen(false)
  {
  }

//--------------------
long CalcThread::Run()
  {
  enum
    {
    MS_PER_FRAME = 10
    }; //min 30
  clock_t start = 0;
  clock_t end = 0;
  while (!mDone)
    {
    if (!mFrozen)
      {
      //calculate an updated grid
      start = clock();
      mGrid.Calculate();
      end = clock();

      //refresh the screen
      mWin.PostEvent(mCallBackId, 0, 0);
      }

    //delay until end of the frame, so we get at most 1 frame per MS_PER_FRAME milliseconds
    //1 tick = 1/CLOCKS_PER_SEC seconds
    if (end <= start)
      {
      Sleep(MS_PER_FRAME);
      }
    else
      {
      clock_t elapsed = end - start;
      clock_t towait = MS_PER_FRAME - elapsed;

      if (towait > MS_PER_FRAME)
        towait = MS_PER_FRAME;
      if (towait == 0)
        towait = MS_PER_FRAME;
      //std::cout << "x=towait=" << towait << std::endl;
      if (towait > 0)
        Sleep(towait);
      }
    }
  return 0;
  }

//----
void CalcThread::End()
  {
  mDone = true;
  }

//----
void CalcThread::Freeze()
  {
  mFrozen = true;
  }
//----
void CalcThread::Unfreeze()
  {
  mFrozen = false;
  }

CalcThread.h

Synopsis
#ifndef CALCTHREAD_H_
#define CALCTHREAD_H_

#include "jBaseThread.h"

class jFrameWin;
class Grid;
class CalcThread : public jBaseThread
  {
  public:
    CalcThread(jFrameWin& w, unsigned short callbackid, Grid& g);
    long Run();
    void End();
    void Freeze();
    void Unfreeze();

  private:
    jFrameWin& mWin;
    Grid& mGrid;
    unsigned short mCallBackId;
    bool mDone;
    bool mFrozen;
  };

#endif /*CALCTHREAD_H_*/

Cell.cpp

Synopsis
#include "Animal.h"
#include "EnvironmentInfo.h"
#include "GridInfo.h"
#include "Cell.h"
#include <stdlib.h>
#include <iostream>

static jColor WHITE(255, 255, 255);
static jColor SUNSHINE(255, 255, 0);

static jColor GREEN9(0, 180, 0);
static jColor GREEN8(0, 205, 0);
static jColor GREEN7(0, 238, 0);
static jColor GREEN6(35, 255, 0);
static jColor GREEN5(75, 255, 0);
static jColor GREEN4(100, 255, 0);
static jColor GREEN3(127, 255, 25);
static jColor GREEN2(150, 255, 47);
static jColor GREEN1(173, 255, 80);
static jColor GREEN0(202, 255, 112);

static jColor DIRT0(240, 230, 140);

//---------
Cell::Cell() :
  color(WHITE), mHasSunshine(false), mPlantLife(0), mDirt(0)
  {
  }

void Cell::InitAnimal()
  {
  mAnimal.SetInitial(gMasterAnimal);
  }

//--
void Cell::SetSunshine()
  {
  int sun = rand() % 100;
  if (sun < gEnvironment.SunPercentage)
    mHasSunshine = true;
  else
    mHasSunshine = false;
  }

//--
void Cell::UpdateColors()
  {
  if (mAnimal.Exists())
    color = mAnimal.GetColor();
  else if (mPlantLife > 90)
    color = GREEN9;
  else if (mPlantLife > 80)
    color = GREEN8;
  else if (mPlantLife > 70)
    color = GREEN7;
  else if (mPlantLife > 60)
    color = GREEN6;
  else if (mPlantLife > 50)
    color = GREEN5;
  else if (mPlantLife > 40)
    color = GREEN4;
  else if (mPlantLife > 30)
    color = GREEN3;
  else if (mPlantLife > 20)
    color = GREEN2;
  else if (mPlantLife > 10)
    color = GREEN1;
  else if (mPlantLife > 0)
    color = GREEN0;

  else if (mDirt > 0)
    color = DIRT0;
  else if (mHasSunshine)
    color = SUNSHINE;
  else
    color = WHITE;
  }

void Cell::UpdatePlantLife()
  {
  if (mHasSunshine)
    {
    //if there's dirt, plants grow faster
    if (mDirt > 0)
      {
      mPlantLife += gEnvironment.PlantLifeIncWithDirt;
      mDirt--; //use up the dirt
      }
    else
      {
      mPlantLife += gEnvironment.PlantLifeIncWithoutDirt;
      }
    }
  else if (mPlantLife >= gEnvironment.PlantLifeDecWithoutSunshine) //no sunshine, high plantlife
    {
    mPlantLife -= gEnvironment.PlantLifeDecWithoutSunshine;
    }
  else //no sunshine, plantlife is dead
    {
    //there was some plants, convert it to dirt
    if (mPlantLife > 0)
      mDirt++;
    mPlantLife = 0;
    }

  if (mPlantLife > 100)
    mPlantLife = 100;
  else if (mPlantLife < 0)
    mPlantLife = 0;
  }

void Cell::UpdateAnimal(int row, int col)
  {
  //if it's dead, check if a new animal should be created 
  if (!mAnimal.Exists())
    {
    CreateNewAnimal(row, col);
    return;
    }

  //it's alive, so eat and make babies
  mAnimal.Update(mPlantLife);

  if (mAnimal.IsSociable())
    {
    MoveCloserToFriend(row, col);
    }
  else if (mAnimal.NotEnoughFood(mPlantLife))
    {
    //if current plantlife is low but animal has enough strength to move
    //try to find more food...
    MoveCloserToFood(row, col);
    }

  if (mAnimal.Exists())
    {
    //a live animal produces "dirt" every day
    mDirt++;
    }
  else
    {
    //a dead animal produces a bit more "dirt"
    mDirt += 2;
    }
  }

void Cell::MoveCloserToFood(int row, int col)
  {
  // move to a vacant neighboring square with the highest green
  int bestrow = -1;
  int bestcol = -1;
  int bestgreen = -1;

  int otherrow;
  int othercol;

  //row above
  otherrow = row - 1;
  othercol = col - 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  otherrow = row - 1;
  othercol = col;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  otherrow = row - 1;
  othercol = col + 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  //current row
  otherrow = row;
  othercol = col - 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  otherrow = row;
  othercol = col + 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  //row below
  otherrow = row + 1;
  othercol = col - 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  otherrow = row + 1;
  othercol = col;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  otherrow = row + 1;
  othercol = col + 1;
  if (IsBetterFood(otherrow, othercol, bestgreen))
    {
    bestrow = otherrow;
    bestcol = othercol;
    }

  //found the best neighboring cell, so move...
  if (bestrow != -1 && bestgreen > 0)
    {
    //move to the best neighboring cell, but it costs some energy to move...
    Cells[bestrow][bestcol].mAnimal.Move(mAnimal);
    }
  }

// check if the grass is greener...
bool Cell::IsBetterFood(int r, int c, int& bestgreen)
  {
  if (r >= 0 && r < GridInfo::numrows && //is row in the grid bounds?
      c >= 0 && c < GridInfo::numcols && // is col in the grid bounds?
      !Cells[r][c].mAnimal.Exists()) // is the cell empty?
    {
    if (Cells[r][c].mPlantLife > bestgreen) // is the plantlife better than we've ever seen?
      {
      bestgreen = Cells[r][c].mPlantLife;
      return true;
      }
    }

  return false;
  }

void Cell::MoveCloserToFriend(int row, int col)
  {
  int bestrow = -1;
  int bestcol = -1;
  int bestenergy = -1;

  //initialize to the current cell's energy
  //if it's the highest energy in the pack, it doesn't move
  //all the other cells will move closer to it.
  mAnimal.IsHigherThenSet(bestenergy);

  int movetorow;
  int movetocol;

  //row above
  movetorow = row - 1;
  movetocol = col - 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row - 1, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row - 2, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row - 2, col - 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row - 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row - 1;
  movetocol = col;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row - 2, col - 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row - 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row - 2, col + 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row - 1;
  movetocol = col + 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row - 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row - 2, col + 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row - 2, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row - 1, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row;
  movetocol = col + 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row - 1, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row + 1, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row + 1;
  movetocol = col + 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 1, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row + 2, col + 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 2, col + 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row + 1;
  movetocol = col;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row + 2, col + 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 2, col - 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row + 1;
  movetocol = col - 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row + 2, col, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 2, col - 1, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }

    if (IsBetterFriend(row + 2, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row + 1, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  movetorow = row;
  movetocol = col - 1;
  if (movetorow >= 0 && movetorow < GridInfo::numrows && //is row in the grid bounds?
      movetocol >= 0 && movetocol < GridInfo::numcols && // is col in the grid bounds?
      !Cells[movetorow][movetocol].mAnimal.Exists() && // the space is empty
      Cells[movetorow][movetocol].mPlantLife >= mPlantLife) //and the grass is ok
    {
    if (IsBetterFriend(row + 1, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    if (IsBetterFriend(row - 1, col - 2, bestenergy))
      {
      bestrow = movetorow;
      bestcol = movetocol;
      }
    }

  //found the best neighboring cell, so move...
  if (bestrow != -1 && bestenergy > 0)
    {
    //std::cout << "move " << row << "," << col << " to " << bestrow << "," << bestcol << std::endl;
    //move closer to the friend cell, but it costs some energy to move...
    Cells[bestrow][bestcol].mAnimal.Move(mAnimal);
    }
  }

bool Cell::IsBetterFriend(int friendr, int friendc, int& bestenergy)
  {
  return friendr >= 0 && friendr < GridInfo::numrows && //is row in the grid bounds?
      friendc >= 0 && friendc < GridInfo::numcols && // is col in the grid bounds?
      Cells[friendr][friendc].mAnimal.Exists() && //friend exists
      Cells[friendr][friendc].mAnimal.IsHigherThenSet(bestenergy);
  }

void Cell::CreateNewAnimal(int row, int col)
  {
  //create a new animal if there are:
  //   - two occupied bordering cells 
  //   - both with energy above a threshold
  //   - choose parents with the highest energy
  //   - the child's energy is a minimum value + a random extra value dependant on parent's energy
  //   - the child's energy will be subtracted from the parents

  // find two parents in occupied neighboring squares
  int parent1row = -1;
  int parent1col = -1;
  int parent1energy = -1;

  int parent2row = -1;
  int parent2col = -1;
  int parent2energy = -1;

  int otherrow;
  int othercol;

  //    >be1 &&  >be2 choose be1
  //    >be1 && <=be2 choose be1
  //   <=be1 &&  >be2 choose be2
  //   <=be1 && <=be2 skip
  //row above
  otherrow = row - 1;
  othercol = col - 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  otherrow = row - 1;
  othercol = col;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  otherrow = row - 1;
  othercol = col + 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  //current row
  otherrow = row;
  othercol = col - 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  otherrow = row;
  othercol = col + 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  //row below
  otherrow = row + 1;
  othercol = col - 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  otherrow = row + 1;
  othercol = col;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  otherrow = row + 1;
  othercol = col + 1;
  if (IsBetterParent(otherrow, othercol, parent1energy))
    {
    parent1row = otherrow;
    parent1col = othercol;
    }
  else if (IsBetterParent(otherrow, othercol, parent2energy))
    {
    parent2row = otherrow;
    parent2col = othercol;
    }

  //check if both parents were found...
  // if they are above the threshold, then the cell is occupied
  if (mAnimal.CanBeBorn(parent1energy, parent2energy))
    {
    mAnimal.BeBorn(Cells[parent1row][parent1col].mAnimal, Cells[parent2row][parent2col].mAnimal);
    Cells[parent1row][parent1col].mAnimal.AdjustParentForBirthOf(mAnimal);
    Cells[parent2row][parent2col].mAnimal.AdjustParentForBirthOf(mAnimal);
    }
  }

bool Cell::IsBetterParent(int r, int c, int& bestenergy)
  {
  return r >= 0 && r < GridInfo::numrows && //is row in the grid bounds?
      c >= 0 && c < GridInfo::numcols && // is col in the grid bounds?
      Cells[r][c].mAnimal.Exists() && Cells[r][c].mAnimal.IsHigherThenSet(bestenergy);
  }


Cell.h

Synopsis
#ifndef CELL_H_
#define CELL_H_

#include "jColor.h"
#include "jRect.h"
#include "Animal.h"

class Cell
  {
  public:
    Cell();
    void UpdateColors();
    void InitAnimal();
    void UpdateAnimal(int row, int col);
    void UpdatePlantLife();
    void SetSunshine();
    int GetType()
      {
      return mAnimal.GetType();
      }

    jColor color;
    jRect rect;

  private:
    void MoveCloserToFood(int row, int col);
    bool IsBetterFood(int r, int c, int& bestgreen);
    void CreateNewAnimal(int row, int col);
    bool IsBetterParent(int r, int c, int& bestenergy);
    void MoveCloserToFriend(int row, int col);
    bool IsBetterFriend(int friendr, int friendc, int& bestenergy);

    //a cell can contain sunshine, plantlife, dirt and an animal (all optional)
    Animal mAnimal;
    bool mHasSunshine;
    int mPlantLife;
    int mDirt;
  };

#endif /*CELL_H_*/

CLArguments.cpp

Synopsis
#include "CLArguments.h"

CLArguments::CLArguments(void)
  {
  mError = false;
  }
CLArguments::~CLArguments(void)
  {
  }
void CLArguments::ProcessArg(char* arg)
  {
  if (IsSwitch(arg))
    ProcessSwitch(arg);
  else
    SetPositionalArg(arg);
  }
void CLArguments::SetPositionalArg(char* arg)
  {
  if (mSourceName.empty())
    mSourceName = arg;
  else if (mTargetName.empty())
    mTargetName = arg;
  else
    {
    mError = true;
    throw std::string("unknown parameter");
    }
  }
bool CLArguments::IsGui()
  {
  return true;
  }
bool CLArguments::IsConsole()
  {
  return !mSourceName.empty() && !mTargetName.empty();
  }
bool CLArguments::IsValid()
  {
  return !mError && (IsConsole() || IsGui());
  }
bool CLArguments::IsSwitch(char* arg)
  {
  return *arg == '-' || *arg == '/';
  }
void CLArguments::ProcessSwitch(char* arg)
  {
  switch (toupper(arg[1]))
    {
    //    case 'M': lpszMergedOutput = arg+2; break;
    case '?':
      throw std::string("help");
    default:
      throw std::string("unknown switch: '") + std::string(arg) + std::string("'");
    }
  }

CLArguments.h

Synopsis
#pragma once
#include <string>
#include <ostream>

class CLArguments
  {
  public:
    CLArguments(void);
    ~CLArguments(void);
    void ProcessArg(char* arg);
    bool IsValid();
    bool IsGui();
    bool IsConsole();

  private:
    void SetPositionalArg(char* arg);
    bool IsSwitch(char* arg);
    void ProcessSwitch(char* arg);

    bool mError;
    std::string mSourceName;
    std::string mTargetName;
  };

EnvironmentInfo.h

Synopsis
#ifndef ENVIRONMENTINFO_H_
#define ENVIRONMENTINFO_H_

class EnvironmentInfo
  {
  public:
    int SunPercentage;
    int PlantLifeIncWithDirt;
    int PlantLifeIncWithoutDirt;
    int PlantLifeDecWithoutSunshine;
    bool UseGenetics;
  };

extern EnvironmentInfo gEnvironment;

#endif /*ENVIRONMENTINFO_H_*/

Grid.cpp

Synopsis
#include "GridInfo.h"
#include "Grid.h"
#include "jGraphics.h"
#include "EnvironmentInfo.h"
#include "Animal.h"

//#include "jGDIResourceLeak.h"
#include <iostream>
#include <stdlib.h>
#include <sstream>

//The grid
Cell Cells[GridInfo::numrows][GridInfo::numcols];
EnvironmentInfo gEnvironment;

static jColor WHITE(255, 255, 255);

//---------
void Grid::Init()
  {
  std::cout << "Grid::init " << std::endl;

  InitEnvironment();
  ReInit();
  }

//---------
void Grid::ReInit()
  {
  std::cout << "Grid::reinit " << std::endl;

  InitGrid();
  InitAnimal();
  Calculate();
  }

void Grid::InitEnvironment()
  {
  //init the environment
  gEnvironment.SunPercentage = 32; //the percentage of time the sun is shining in a cell
  gEnvironment.PlantLifeIncWithDirt = 6; //the plant life increment with sun & dirt
  gEnvironment.PlantLifeIncWithoutDirt = 3; //the plant life increment with sun & no dirt
  gEnvironment.PlantLifeDecWithoutSunshine = 1; //the plant life decrement with no sun & no dirt
  gEnvironment.UseGenetics = false; //do not use genetics for birthing babies

  gMasterAnimal.Init();
  }

//---------
void Grid::Calculate()
  {
  //std::cout << "x=Grid::Calculate " << std::endl;
  UpdateSunshine();
  UpdatePlantLife();
  UpdateAnimal();
  UpdateColors();
  }

//---------
//-- update colors
void Grid::UpdateColors()
  {
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      Cells[row][col].UpdateColors();
      }
    }
  }

//---------
//-- update colors
void Grid::InitAnimal()
  {
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      Cells[row][col].InitAnimal();
      }
    }
  }

//---------
//-- update colors
void Grid::UpdateAnimal()
  {
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      Cells[row][col].UpdateAnimal(row, col);
      }
    }
  }

//---------
//-- update colors
void Grid::UpdatePlantLife()
  {
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      Cells[row][col].UpdatePlantLife();
      }
    }
  }

//---------
//-- update sunshine
void Grid::UpdateSunshine()
  {
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      Cells[row][col].SetSunshine();
      }
    }
  }

//---------
void Grid::InitGrid()
  {
  jRect rct;
  rct.x = 1;
  rct.y = 1;
  rct.width = GridInfo::colwidth - 1;
  rct.height = GridInfo::rowheight - 1;

  //set up the grid
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      //calculate cell size
      rct.x = (col * GridInfo::colwidth) + 1;
      rct.y = (row * GridInfo::rowheight) + 1;
      Cells[row][col].rect = rct;
      }
    }
  }

//---------
void Grid::Update(int inc)
  {
  std::cout << "Grid::update " << std::endl;

  jColor color;
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      color = Cells[row][col].color;
      color.red += inc;
      color.green += inc;
      color.blue += inc;
      Cells[row][col].color = color;
      //      std::cout << "update   inc=" << inc << " r=" << (int) Cells[row][col].color.red << " g="
      //          << (int) Cells[row][col].color.green << " b=" << (int) Cells[row][col].color.blue
      //          << std::endl;
      }
    }
  }

template <typename T>
void DrawLabelAndValue(jGraphics& g, const jRect& rct, const std::string& label, T value)
  {
  std::stringstream s;
  s << label << value << std::endl;
  g.FillRect(WHITE, rct);
  g.Text(s.str(), rct);
  }

void DrawLabel(jGraphics& g, const jRect& rct, const std::string& label)
  {
  std::stringstream s;
  s << label << std::endl;
  g.FillRect(WHITE, rct);
  g.Text(s.str(), rct);
  }

//---------
//-- paint the current grid
void Grid::Paint(jGraphics& g, int gen)
  {
  //std::cout << "Grid::paint " << std::endl;
  int count[512];
  memset(&count, 0x00, sizeof(count));
  for (int col = 0; col < GridInfo::numcols; ++col)
    {
    for (int row = 0; row < GridInfo::numrows; ++row)
      {
      g.FillRect(Cells[row][col].color, Cells[row][col].rect);
      int type = Cells[row][col].GetType();
      if (type > 0 && type < 512)
        {
        count[type]++;
        }
      else
        {
        count[0]++;
        }
      }
    }

  if (count[1] == 0)
    {
    count[1] = 0;
    }

  for (int col = 0; col <= GridInfo::numcols; ++col)
    {
    g.Line(col * GridInfo::colwidth, 0, col * GridInfo::colwidth, GridInfo::numrows
        * GridInfo::rowheight);
    }
  for (int row = 0; row <= GridInfo::numrows; ++row)
    {
    g.Line(0, row * GridInfo::rowheight, GridInfo::numcols * GridInfo::colwidth, row
        * GridInfo::rowheight);
    }

  jRect rct;
  rct.x = (GridInfo::numcols * GridInfo::colwidth) + 50;
  rct.y = 0;
  rct.height = 20;
  rct.width = 300;

  DrawLabelAndValue(g, rct, "Generation: ", gen);
  rct.y += 20; //next line
  DrawLabelAndValue(g, rct, "Non-animals : ", count[0]);
  rct.y += 20; //next line
  for (int i = 1; i < 20; i++)
    {
    std::stringstream s;
    s << "Animal" << i << " Pop.: ";
    DrawLabelAndValue(g, rct, s.str(), count[i]);
    rct.y += 20; //next line
    }

  rct.y += 20; //next line

  DrawLabel(g, rct, "Environment:");
  rct.x += 10; //indent a little
  rct.y += 20; //next line
  DrawLabelAndValue(g, rct, "Sun: ", gEnvironment.SunPercentage);
  rct.y += 20; //next line
  DrawLabel(g, rct, "Plant Life: ");
  rct.y += 20; //next line
  rct.x += 10; //indent a little
  DrawLabelAndValue(g, rct, "With sun + dirt  : ", gEnvironment.PlantLifeIncWithDirt);
  rct.y += 20; //next line
  DrawLabelAndValue(g, rct, "With sun, no dirt: ", gEnvironment.PlantLifeIncWithoutDirt);
  rct.y += 20; //next line
  DrawLabelAndValue(g, rct, "No sun, no dirt  : ", gEnvironment.PlantLifeDecWithoutSunshine);
  rct.y += 20; //next line

  DrawLabelAndValue(g, rct, "Use Genetics     : ", gEnvironment.UseGenetics);
  rct.y += 20; //next line

  rct.x -= 10; //undent a little
  rct.x -= 10; //undent a little
  DrawLabel(g, rct, "Animal:");
  rct.x += 10; //indent a little
  rct.y += 20; //next line
  DrawLabelAndValue(g, rct, "Sociability: ", gMasterAnimal.Sociability);

  //  rct.y += 20; //next line
  //  rct.y += 20; //next line
  //  rct.x = (GridInfo::numcols * GridInfo::colwidth) + 50;
  //  DrawLabel(g, rct, "Animal1:");
  //  rct.y += 20; //next line
  //  rct.x += 10; //indent a little
  //  //int ExistsPercentage;
  //  DrawLabelAndValue(g, rct, "Energy to move : ", mAnimal1.EnergyToMove);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Plants eaten/day : ", mAnimal1.PlantsEatenPerDay);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Energy from Plants/day : ", mAnimal1.EnergyGainedByEatingPlants);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Energy lost/day : ", mAnimal1.EnergyLossPerDay);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Youth threshold: ", mAnimal1.YoungThreshold);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Youth Energy Loss (%): ", mAnimal1.PercentageEnergyLossYoung);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Old Age threshold: ", mAnimal1.OldThreshold);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Old Age Energy Loss (%): ", mAnimal1.PercentageEnergyLossOld);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Energy to be a parent: ", mAnimal1.ParentEnergyThreshold);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Child's minimum energy: ", mAnimal1.ChildMinimumEnergy);
  //  rct.y += 20; //next line
  //  DrawLabelAndValue(g, rct, "Child's additional energy(%): ", mAnimal1.ChildPercentageAdditionalEnergy);
  }

Grid.h

Synopsis
#ifndef GRID_H_
#define GRID_H_

#include "jColor.h"
#include "jRect.h"
#include "Animal.h"

class jGraphics;
class Grid
  {
  public:
    void Init();
    void ReInit();
    void Update(int inc);
    void Calculate();
    void Paint(jGraphics& g, int gen);

  private:
    void InitEnvironment();
    void InitGrid();
    void InitAnimal();
    void UpdateColors();
    void UpdateSunshine();
    void UpdatePlantLife();
    void UpdateAnimal();

    //EnvironmentInfo mEnv;
    //Animal mAnimal1;
  };

#endif /*GRID_H_*/

GridInfo.h

Synopsis
#ifndef GRIDINFO_H_
#define GRIDINFO_H_

#include "Cell.h"

namespace GridInfo
  {
  enum
    {
    numrows = 150, numcols = 150, colwidth = 3, rowheight = 3,
    };
  }

extern Cell Cells[GridInfo::numrows][GridInfo::numcols];

#endif /*GRIDINFO_H_*/

Help.cpp

Synopsis
#include "Help.h"
#include <iostream>

Help::Help(void)
  {
  mHelpPrinted = false;
  }
Help::~Help(void)
  {
  }
bool Help::isPrinted()
  {
  return mHelpPrinted;
  }
void Help::printOn(std::ostream& os)
  {
  if (mHelpPrinted)
    return;
  os << "\nUsage: jLife \n"
    "Optional switches (use either - or /):\n"
    "/?            This help\n" << std::endl;
  mHelpPrinted = true;
  }


Help.h

Synopsis
#pragma once
#include <ostream>

class Help
  {
  public:
    Help(void);
    ~Help(void);
    void printOn(std::ostream& os);
    bool isPrinted();

  private:
    bool mHelpPrinted;
  };

jBaseThread.cpp

Synopsis
#include "jBaseThread.h"
#include <wtypes.h>

//todo: clean up thread! resource leak. 

//----
static DWORD WINAPI theThread(LPVOID parm)
  {
  return ((jBaseThread*) parm)->Run();
  }

class jBaseThread::Private
  {
  public:
    DWORD Tid;
  };

//----
jBaseThread::jBaseThread() :
  mPrivate(*new jBaseThread::Private())
  {
  }

//----
void jBaseThread::Start()
  {
  ::CreateThread(0, 0, theThread, (LPVOID) this, 0, &mPrivate.Tid);
  }

jBaseThread.h

Synopsis
#pragma once

//-------------------------
class jBaseThread
  {
  public:
    jBaseThread();
    void Start();
    virtual long Run() = 0;

  private:
    class Private;
    Private& mPrivate;
  };

jCanvas.h

Synopsis
#pragma once

class jCanvas
  {
  public:
    jCanvas()
      {
      }
    ~jCanvas()
      {
      }

  private:
    //class Private;
    //Private& mPrivate;
  };

jColor.h

Synopsis
#ifndef JCOLOR_H_
#define JCOLOR_H_

struct jColor
  {
    unsigned char red;
    unsigned char green;
    unsigned char blue;

    jColor() :
      red(0), green(0), blue(0) //default to black
      {
      }
    jColor(unsigned char r, unsigned char g, unsigned char b) :
      red(r), green(g), blue(b)
      {
      }
    jColor& operator =(const jColor& other)
      {
      red = other.red;
      green = other.green;
      blue = other.blue;
      return *this;
      }
  };

#endif /*JCOLOR_H_*/

jComponentList.h

Synopsis
#pragma once

#include <list>

class jWinComponent;
typedef std::list<jWinComponent*> jComponentList;

jDialog.cpp

Synopsis
#include "jDialog.h"
#include "jNativeWin.h"

class jDialog::Private
  {
  public:
    jNativeDialog mWin;
  };

jDialog::jDialog(void) :
  mPrivate(*new jDialog::Private())
  {

  }

jDialog::~jDialog(void)
  {
  delete &mPrivate;
  }

void jDialog::Create(const jWin& parent, const std::string& title, const jRect& rct)
  {
  mPrivate.mWin.Create(parent, title, rct);
  }

void jDialog::Create(const jWin& parent, const std::string& title, int x, int y, int width,
                     int height)
  {
  jRect rct;
  rct.x = x;
  rct.y = y;
  rct.width = width;
  rct.height = height;

  Create(parent, title, rct);
  }

//void jDialog::Text(const std::string& s)
//  {
//  mPrivate.mWin.Text(s);
//  }

unsigned long  jDialog::Show()
  {
  return mPrivate.mWin.Show();
  }

void jDialog::AddEdit(int defaultvalue, int& variable, int x, int y, int width, int height)
  {
  jRect rct;
  rct.x = x;
  rct.y = y;
  rct.width = width;
  rct.height = height;
  AddEdit(defaultvalue, variable, rct);
  }
void jDialog::AddEdit(int defaultvalue, int& variable, const jRect& rct)
  {
  mPrivate.mWin.AddEdit(defaultvalue, variable, rct);
  }

void jDialog::AddEdit(double defaultvalue, double& variable, int x, int y, int width, int height)
  {
  jRect rct;
  rct.x = x;
  rct.y = y;
  rct.width = width;
  rct.height = height;
  AddEdit(defaultvalue, variable, rct);
  }
void jDialog::AddEdit(double defaultvalue, double& variable, const jRect& rct)
  {
  mPrivate.mWin.AddEdit(defaultvalue, variable, rct);
  }

//void jDialog::AddEntry(const std::string& label, int& variable, int x, int y, int labelwidth,
//                       int entrywidth, int height)
//  {
//  mPrivate.mWin.AddEntry(label, variable, x, y, labelwidth, entrywidth, height);
//  }

void jDialog::AddButton(const std::string& label, DialogCallBack& cmd, int x, int y, int width,
                        int height)
  {
  jRect rct;
  rct.x = x;
  rct.y = y;
  rct.width = width;
  rct.height = height;
  AddButton(label, cmd, rct);
  }

void jDialog::AddButton(const std::string& label, DialogCallBack& cmd, const jRect& rct)
  {
  mPrivate.mWin.AddButton(label, cmd, rct);
  }

void jDialog::AddLabel(const std::string& label, int x, int y, int width, int height)
  {
  jRect rct;
  rct.x = x;
  rct.y = y;
  rct.width = width;
  rct.height = height;
  AddLabel(label, rct);
  }

void jDialog::AddLabel(const std::string& label, const jRect& rct)
  {
  mPrivate.mWin.AddLabel(label, rct);
  }

void jDialog::Close(unsigned long returncode)
  {
  mPrivate.mWin.Close(returncode);
  }

//void jDialog::AddEntry(const std::string& label, double& variable, int x, int y, int labelwidth, int entrywidth, int height);
//void jDialog::AddEntry(const std::string& label, std::string& variable, int x, int y, int labelwidth, int entrywidth, int height);
//void jDialog::SetSize(int width, int height);

jDialog.h

Synopsis
#pragma once

#include "jICallBack.h"
#include <string>

class jWin;
class jRect;
class jDialog
  {
  public:
    jDialog(void);
    ~jDialog(void);

    void Create(const jWin& parent, const std::string& title, const jRect& rct);
    void Create(const jWin& parent, const std::string& title, int x, int y, int width, int height);
    //void Text(const std::string& s);
    void AddEdit(int defaultvalue, int& variable, int x, int y, int width, int height);
    void AddEdit(int defaultvalue, int& variable, const jRect& rct);
    void AddEdit(double defaultvalue, double& variable, int x, int y, int width, int height);
    void AddEdit(double defaultvalue, double& variable, const jRect& rct);
//    void AddEntry(const std::string& label, int& variable, int x, int y, int labelwidth,
//                  int entrywidth, int height);
    void AddButton(const std::string& label, DialogCallBack& cmd, int x, int y, int width,
                   int height);
    void AddButton(const std::string& label, DialogCallBack& cmd, const jRect& rct);
    void AddLabel(const std::string& label, int x, int y, int width, int height);
    void AddLabel(const std::string& label, const jRect& rct);
    unsigned long Show();
    void Close(unsigned long returncode);

    //void AddEntry(const std::string& label, double& variable, int x, int y, int labelwidth, int entrywidth, int height);
    //void AddEntry(const std::string& label, std::string& variable, int x, int y, int labelwidth, int entrywidth, int height);
    //void SetSize(int width, int height);

  private:
    class Private;
    Private& mPrivate;
  };

jFrameWin.cpp

Synopsis
#include "jframewin.h"
#include "jNativeWin.h"
#include "jLayoutMgrEvenColumns.h"
#include "jMenu.h"
#include "jWinComponent.h"

//------------------------------------------------
class jFrameWin::Private
  {
  public:
    jNativeFrameWin mWin;
    jComponentList mComponents;
  };

jWin jFrameWin::getWin()
  {
  return mPrivate.mWin.GetWin();
  }
//------------------------------------------------
jFrameWin::jFrameWin(void) :
  mPrivate(*new jFrameWin::Private())
  {
  }
//------------------------------------------------
jFrameWin::~jFrameWin(void)
  {
  delete &mPrivate;
  }

//------------------------------------------------
void jFrameWin::Add(jWinComponent& win)
  {
  win.SetOwnerTo(mPrivate.mWin.GetWin());
  mPrivate.mComponents.push_back(&win);
  }

//------------------------------------------------
void jFrameWin::Text(const std::string& s)
  {
  mPrivate.mWin.Text(s.c_str());
  }

//------------------------------------------------
void jFrameWin::Create(void)
  {
  mPrivate.mWin.CreateSkeletonWindow("jFrameWinClass");
  }
//------------------------------------------------
void jFrameWin::Close()
  {
  mPrivate.mWin.Close();
  }
//------------------------------------------------
long jFrameWin::Show(void)
  {
  //Layout(); todo: this code blows up if mPrivate.mComponents is empty
  mPrivate.mWin.Show();
  return mPrivate.mWin.StartMessageLoop();
  }
//------------------------------------------------
void jFrameWin::SetActive(void)
  {
  mPrivate.mWin.SetActive();
  }

//------------------------------------------------
void jFrameWin::SetSize(int width, int height)
  {
  mPrivate.mWin.SetSize(width, height);
  }

//------------------------------------------------
void jFrameWin::Redraw(void)
  {
  mPrivate.mWin.Redraw();
  }
//------------------------------------------------
void jFrameWin::Layout()
  {
  jLayoutMgrEvenColumns lm(2, 2);
  lm.onLayout(mPrivate.mWin.GetSize(), mPrivate.mComponents);
  }
//------------------------------------------------
jMenu jFrameWin::AddMenu() const
  {
  return jMenu::Create(mPrivate.mWin);
  }

void jFrameWin::AddOnPaintCallBack(PaintCallBack& cmd) const
  {
  mPrivate.mWin.AddOnPaintCallBack(cmd);
  }
void jFrameWin::PostEvent(unsigned short id, unsigned int parm1, unsigned int parm2)
  {
  mPrivate.mWin.PostEvent(id, parm1, parm2);
  }
void jFrameWin::AddGenericCallBack(unsigned short id, GenericCallBack& cmd) const
  {
  mPrivate.mWin.AddGenericCallBack(id, cmd);
  }


jFrameWin.h

Synopsis
#pragma once

#include "jMenu.h"
#include "jICallBack.h"
#include <string>

//todo: ugh
#include "jWin.h"

class jWinComponent;

class jFrameWin
  {
  public:
    jFrameWin(void);
    ~jFrameWin(void);
    jWin getWin();

    void Create();
    void Close();
    long Show();
    void SetActive();
    void Redraw();
    void Text(const std::string& s);
    void Add(jWinComponent& wcomp);
    void SetSize(int width, int height);

    jMenu AddMenu() const;
    void AddOnPaintCallBack(PaintCallBack& cmd) const;

    void PostEvent(unsigned short id, unsigned int parm1, unsigned int parm2);
    void AddGenericCallBack(unsigned short id, GenericCallBack& cmd) const;

  private:
    void Layout();
    class Private;
    Private& mPrivate;
  };

jFunctor.h

Synopsis
#pragma once

#include "jTypeList.h"

namespace jFunctor
  {
  template <typename T, class TList> class FnImpl;

  //---
  template <typename R> class FnImpl<R, TYPELIST0()>
    {
    public:
      virtual ~FnImpl()
        {
        }
      virtual R operator()() = 0;
    };

  //---
  template <typename R, typename P1> class FnImpl<R, TYPELIST1(P1) >
    {
    public:
      virtual ~FnImpl()
        {
        }
      virtual R operator()(P1) = 0;
    };

  //---
  template <typename R, typename P1, typename P2> class FnImpl<R, TYPELIST2(P1, P2) >
    {
    public:
      virtual ~FnImpl()
        {
        }
      virtual R operator()(P1, P2) = 0;
    };

  //---
  template <class ParentFn, typename PointerToObj, typename PointerToMemFn> class MemFnHandler : public FnImpl<
      typename ParentFn::ResultType, typename ParentFn::ParmList>
    {
    public:
      typedef typename ParentFn::ResultType ResultType;

      //--
      MemFnHandler(const PointerToObj& pObj, PointerToMemFn pMemFn) :
        mObj(pObj), mMemFn(pMemFn)
        {
        }

      //--
      ResultType operator()()
        {
        return ((*mObj).*mMemFn)();
        }

      //--
      ResultType operator()(typename ParentFn::TParm1 p1)
        {
        return ((*mObj).*mMemFn)(p1);
        }

      //--
      ResultType operator()(typename ParentFn::TParm1 p1, typename ParentFn::TParm2 p2)
        {
        return ((*mObj).*mMemFn)(p1, p2);
        }

    private:
      PointerToObj mObj;
      PointerToMemFn mMemFn;
    };

  //---
  template <typename R, class TList> class Fnct
    {
    public:
      typedef R ResultType;
      typedef TList ParmList;
      typedef typename TL::TypeAt<TList, 0, TL::NullType>::Type TParm1;
      typedef typename TL::TypeAt<TList, 1, TL::NullType>::Type TParm2;

      Fnct() :
        spImpl_(0)
        {
        }

      template <typename Obj, typename Fun> Fnct(const Obj& obj, const Fun& fun) :
        spImpl_(new MemFnHandler<Fnct, Obj, Fun> (obj, fun))
        {
        }
      Fnct(const Fnct& other)
        {
        spImpl_ = other.spImpl_;
        }
      Fnct& operator=(const Fnct& other)
        {
        spImpl_ = other.spImpl_;
        return *this;
        }
      //todo: use auto-ptr explicit Functor(std::auto_ptr<Impl> spImpl);

      R operator()()
        {
        return spImpl_->operator ()();
        }

      R operator()(TParm1 p1)
        {
        return spImpl_->operator ()(p1);
        }

      R operator()(TParm1 p1, TParm2 p2)
        {
        return spImpl_->operator ()(p1, p2);
        }

    private:
      typedef FnImpl<R, TList> Impl;
      Impl* spImpl_;
    };
  }

jGDIResourceLeak.cpp

Synopsis
#include "jGDIResourceLeak.h"
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <iostream>

jGDIResourceLeak::jGDIResourceLeak()
  {
  _guiResCount = ::GetGuiResources(::GetCurrentProcess(), GR_GDIOBJECTS);
  }
jGDIResourceLeak::~jGDIResourceLeak()
  {
  int leaks = ::GetGuiResources(::GetCurrentProcess(), GR_GDIOBJECTS) - _guiResCount;
  if (leaks != 0)
    {
    std::cout << "GDI Resources: leaked: " << leaks << " rescount=" << _guiResCount << std::endl;
    }
  else
    {
    std::cout << "GDI Resources: no leaks: " << leaks << " rescount=" << _guiResCount << std::endl;
    }
  }

jGDIResourceLeak.h

Synopsis
#ifndef jGDIRESOURCELEAK_H_
#define jGDIRESOURCELEAK_H_

class jGDIResourceLeak
  {
  public:
    explicit jGDIResourceLeak();
    ~jGDIResourceLeak();
  private:
    unsigned _guiResCount;
  };
#endif /*GDIRESOURCELEAK_H_*/

jGraphics.cpp

Synopsis
#include "jGraphics.h"
#include "jNativeWin.h"
#include "jRect.h"
#include <iostream>

jGraphics::jGraphics(jNativeGraphics& g) :
  mGraphics(g)
  {
  }

jGraphics::~jGraphics()
  {
  ; //nothing to do
  }

void jGraphics::Line(int x1, int y1, int x2, int y2)
  {
  mGraphics.Line(x1, y1, x2, y2);
  }

void jGraphics::FillRect(const jColor& color, int x1, int y1, int x2, int y2)
  {
  jRect rct;
  rct.x = x1;
  rct.y = y1;
  rct.width = x2 - x1;
  rct.height = y2 - y1;

  FillRect(color, rct);
  }

void jGraphics::FillRect(const jColor& color, const jRect& rct)
  {
  mGraphics.FillRect(color, rct);
  }

void jGraphics::Text(const std::string& txt, const jRect& rct)
  {
  mGraphics.Text(txt, rct);
  }

jGraphics.h

Synopsis
#pragma once

#include <string>

class jNativeGraphics;
class jRect;
class jColor;
class jGraphics
  {
  public:
    jGraphics(jNativeGraphics& g);
    ~jGraphics();

    void Line(int x1, int y1, int x2, int y2);
    void FillRect(const jColor& color, int x1, int y1, int x2, int y2);
    void FillRect(const jColor& color, const jRect& rct);
    void Text(const std::string& txt, const jRect& rct);

  private:
    jNativeGraphics& mGraphics;
  };

jICallBack.h

Synopsis
#pragma once
#include <string>
#include "jFunctor.h"

//used for callbacks when a menu item is clicked
//  returns an int
//  parm1: a string indicating the name of the menu item
typedef jFunctor::Fnct<int, TYPELIST1(const std::string&)> MenuCallBack;

//used for OnPaint callbacks
class jGraphics;
typedef jFunctor::Fnct<int, TYPELIST1(jGraphics&)> PaintCallBack;

//used for Generic callbacks
//typedef Functor::Fnct<int, TL::TypeList<unsigned int, unsigned int > > GenericCallBack;
typedef jFunctor::Fnct<int, TYPELIST1(unsigned int)> GenericCallBack;

//used for Dialog button callbacks
typedef jFunctor::Fnct<int, TYPELIST1(const std::string&)> DialogCallBack;

jListBox.cpp

Synopsis
#include "jlistbox.h"
#include "jNativeWin.h"

//------------------------------------------------
class jListBox::Private
  {
  public:
    jNativeListBox mWin;
  };

//------------------------------------------------
jListBox::jListBox() :
  mPrivate(*new jListBox::Private())
  {
  mPrivate.mWin.CreateSkeletonWindow();
  }

//------------------------------------------------
jListBox::~jListBox(void)
  {
  delete &mPrivate;
  }

//------------------------------------------------
void jListBox::SetOwnerTo(const jWin& owner)
  {
  mPrivate.mWin.ConvertToChildWindow();
  mPrivate.mWin.SetParent(owner);
  mPrivate.mWin.SetSize(0, 0, 100, 200);
  mPrivate.mWin.Show();
  }

//------------------------------------------------
void jListBox::SetSize(int x, int y, int width, int height)
  {
  mPrivate.mWin.SetSize(x, y, width, height);
  }

//------------------------------------------------
void jListBox::AddString(const std::string& s)
  {
  mPrivate.mWin.AddString(s.c_str());
  }

jListBox.h

Synopsis
#pragma once

#include "jWinComponent.h"
#include <string>

class jListBox : public jWinComponent
  {
  public:
    jListBox();
    virtual ~jListBox(void);
    void SetOwnerTo(const jWin& owner);
    void SetSize(int x, int y, int width, int height);
    void AddString(const std::string& s);

  private:
    class Private;
    Private& mPrivate;
  };

jMenu.cpp

Synopsis
#include "jMenu.h"
#include "jNativeWin.h"

jMenu jMenu::Create(jNativeFrameWin& nfw)
  {
  return jMenu(nfw);
  }

jMenu::jMenu(jNativeFrameWin& nfw) :
  mMenu(*new jNativeMenu(nfw))
  {
  }

jMenu::~jMenu(void)
  {
  delete &mMenu;
  }

void jMenu::CreateDropDown(const std::string& name)
  {
  mMenu.CreateDropDown(name);
  }
jMenu::MenuItem* jMenu::CreateMenuItem(const std::string& name, MenuCallBack& fn)
  {
  return mMenu.CreateMenuItem(name, fn);
  }

jMenu::MenuItem* jMenu::AddItem(const std::string& name, MenuCallBack& fn)
  {
  return mMenu.AddItem(name, fn);
  }

jMenu.h

Synopsis
#pragma once

#include "jICallBack.h"
#include <string>

class jNativeMenu;
class jNativeFrameWin;

class jMenu
  {
  public:
    class MenuItem
      {
      public:
        virtual void SetMenuItemText(const std::string& newname) = 0;
        virtual void SetEnabled(bool enable) = 0;
      };

    static jMenu Create(jNativeFrameWin& nfw);
    ~jMenu(void);

    void CreateDropDown(const std::string& name);
    MenuItem* CreateMenuItem(const std::string& name, MenuCallBack& fn);
    MenuItem* AddItem(const std::string& name, MenuCallBack& fn);

  private:
    explicit jMenu(jNativeFrameWin& nfw);
    jNativeMenu& mMenu;
  };

jNativeWin.cpp

Synopsis
#include "jNativeWin.h"
#include "jGraphics.h"
#include "jICallBack.h"
#include "jFunctor.h"
#include "jWin.h"
#include "jColor.h"
#include "jRect.h"

//#include "jGDIResourceLeak.h"

#include <windows.h>
#include <windowsx.h>
#include <CommCtrl.h>
#include <map>
#include <iostream>
#include <sstream>

jNativeWin::jNativeWin(void)
  {
  }

jNativeWin::~jNativeWin(void)
  {
  }

jRect jNativeWin::GetSize()
  {
  RECT rct;
  ::GetClientRect((HWND) mWin.mHwnd, &rct);
  jRect jr;
  jr.x = rct.top;
  jr.y = rct.left;
  jr.width = rct.right - rct.left;
  jr.height = rct.bottom - rct.top;
  return jr;
  }

void jNativeWin::CreateSkeletonWindow(const std::string& className)
  {
  mWin.mHwnd = ::CreateWindow(
      className.c_str(), // name of window class
      "", // title-bar string
      WS_POPUP|WS_BORDER, // top-level window
      0, // default horizontal position
      0, // default vertical position
      0, // default width
      0, // default height
      (HWND) 0, // no owner window
      (HMENU) 0, // use class menu
      GetModuleHandle(NULL), // handle to application instance
      (LPVOID) 0); // no window-creation data
  //DWORD gle = GetLastError();
  ::SetWindowLong((HWND) mWin.mHwnd, GWL_USERDATA, (LONG) this);
  }

void jNativeWin::ConvertToChildWindow()
  {
  DWORD style = GetWindowStyle((HWND) mWin.mHwnd);
  style |= WS_CHILD;
  style ^= WS_POPUP;
  ::SetWindowLong((HWND) mWin.mHwnd, GWL_STYLE, style);
  }

void jNativeWin::Text(const std::string& s)
  {
  ::SetWindowText((HWND) mWin.mHwnd, s.c_str());
  }

void jNativeWin::SetParent(const jWin& parent)
  {
  ::SetParent((HWND) mWin.mHwnd, (HWND) parent.mHwnd);
  }

void jNativeWin::SetSize(int x, int y, int width, int height)
  {
  ::SetWindowPos((HWND) mWin.mHwnd, HWND_TOP, x, y, width, height, 0);
  }

void jNativeWin::Show()
  {
  ::ShowWindow((HWND) mWin.mHwnd, SW_SHOW);
  ::UpdateWindow((HWND) mWin.mHwnd);
  }
void jNativeWin::SetActive()
  {
  //::SetActiveWindow((HWND) mWin.mHwnd);
  //::SetForegroundWindow((HWND) mWin.mHwnd);
  ::SetFocus((HWND) mWin.mHwnd); 
  }
void jNativeWin::Close()
  {
  ::PostQuitMessage(0);
  }

void jNativeWin::Redraw()
  {
  //::InvalidateRect((HWND) mWin.mHwnd, 0, TRUE);
  ::InvalidateRect((HWND) mWin.mHwnd, 0, FALSE);
  }

//------------------------------------------------
typedef std::pair<MenuCallBack, std::string> MenuCommandInfo;
typedef std::map<short, MenuCommandInfo> MenuCommandListenerList;
typedef std::map<short, GenericCallBack> GenericCommandListenerList;

class jNativeFrameWin::Private
  {
  public:
    MenuCommandListenerList MenuCommandListeners;
    GenericCommandListenerList GenericCommandListeners;
    PaintCallBack PaintCmd;
  };

jNativeFrameWin::jNativeFrameWin() :
  mPrivate(*new jNativeFrameWin::Private)
  {
  }
void jNativeFrameWin::CreateSkeletonWindow(const std::string& className)
  {
  RegisterWinClass(className);
  CreateFrameWin(className);
  }

//----
class PaintDeviceContext
  {
  public:
    PaintDeviceContext(HWND hwnd)
      {
      mHwnd = hwnd;
      mHdc = ::BeginPaint(mHwnd, &mPaintStruct);
      //      std::cout << "x=: paint: " 
      //                << mPaintStruct.rcPaint.left << " "
      //                << mPaintStruct.rcPaint.right << " "
      //                << mPaintStruct.rcPaint.top << " "
      //                << mPaintStruct.rcPaint.bottom << " "
      //                << std::endl;
      }

    ~PaintDeviceContext()
      {
      ::EndPaint(mHwnd, &mPaintStruct);
      }

    //protected:
    HDC mHdc;
    PAINTSTRUCT mPaintStruct;
    HWND mHwnd;
  };

static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
  jNativeFrameWin* This = (jNativeFrameWin*) ::GetWindowLong(hwnd, GWL_USERDATA);
  if (This == 0)
    return DefWindowProc(hwnd, uMsg, wParam, lParam);

  //is this one of our own messages?
  if (uMsg >= WM_APP && uMsg <= WM_APP + 0x3FFF)
    {
    This->HandleGenericEvent(uMsg - WM_APP, (unsigned int) wParam, (unsigned int) lParam);
    return 0; //todo: use return code from HandleGenericEvent??
    }

  switch (uMsg)
    {
    //WM_CLOSE ; def handler sends a destroy

    //WM_DESTROY; //about to end, cleanup.
    case WM_DESTROY:
      std::cout << "x=wm_destroy: " << std::endl;
      ::PostQuitMessage(0);
      return 0;

      //wParam lo 16 => WM_LBUTTONDOWN(x201), WM_RBUTTONDOWN(x204)
      //wParam hi 16 => child id
      //lParam => hwnd of child
    case WM_PARENTNOTIFY:
      uMsg = uMsg;
      break;

      //wparam lower 16 is the id of the menu item
    case WM_COMMAND:
      if (HIWORD(wParam) == 0)
        {
        This->HandleMenuCommand(LOWORD(wParam));
        }
      return 0;

      //WM_PAINT; redraw the screen
    case WM_PAINT:
      {
      PaintDeviceContext dc(hwnd);
      jNativeGraphics ng((unsigned long) dc.mHdc);
      jGraphics g(ng);
      This->Paint(g);
      }
      return 0;

    default:
      ; //uMsg=uMsg;
    }

  return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }

//--
void jNativeFrameWin::PostEvent(unsigned short id, unsigned int parm1, unsigned int parm2)
  {
  //todo: check if id is registered in GenericCommandListeners
  PostMessage((HWND) mWin.mHwnd, WM_APP + id, parm1, parm2);
  }
void jNativeFrameWin::AddGenericCallBack(unsigned short id, GenericCallBack& cmd) const
  {
  //todo: WM_APP = 0x8000 -> 0xBFFF inclusive, so check if id = 0 -> 16383 inclusive
  mPrivate.GenericCommandListeners[id] = cmd;
  }
void jNativeFrameWin::HandleGenericEvent(unsigned short id, unsigned int parm1, unsigned int parm2)
  {
  GenericCommandListenerList::iterator pos = mPrivate.GenericCommandListeners.find(id);
  if (pos == mPrivate.GenericCommandListeners.end())
    return;
  GenericCallBack cb = pos->second;
  cb(parm1);
  }

//--
void jNativeFrameWin::SetMenuCommandCallBack(short itemid, const std::string& name,
                                             MenuCallBack& fn)
  {
  mPrivate.MenuCommandListeners[itemid] = make_pair(fn, name);
  }
void jNativeFrameWin::UpdateMenuCommandCallBack(short itemid, const std::string& newname)
  {
  MenuCommandListenerList::iterator pos = mPrivate.MenuCommandListeners.find(itemid);
  if (pos == mPrivate.MenuCommandListeners.end())
    return;
  (pos->second).second = newname;
  }
void jNativeFrameWin::HandleMenuCommand(short itemid)
  {
  MenuCommandListenerList::iterator pos = mPrivate.MenuCommandListeners.find(itemid);
  if (pos == mPrivate.MenuCommandListeners.end())
    return;
  MenuCommandInfo info = pos->second;
  (info.first)(info.second);
  }

//--
void jNativeFrameWin::AddOnPaintCallBack(PaintCallBack& cmd) const
  {
  mPrivate.PaintCmd = cmd;
  }

void jNativeFrameWin::Paint(jGraphics& g)
  {
  mPrivate.PaintCmd(g);
  }

void jNativeFrameWin::RegisterWinClass(const std::string& className)
  {
  WNDCLASSEX wclass;
  wclass.cbSize = sizeof(wclass);
  wclass.cbClsExtra = 0;
  wclass.cbWndExtra = 0;
  wclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  wclass.hIcon = LoadIcon(0, IDI_INFORMATION);
  wclass.hInstance = GetModuleHandle(NULL);
  wclass.lpfnWndProc = WindowProc;
  wclass.lpszClassName = className.c_str();
  wclass.lpszMenuName = 0;
  wclass.style = CS_HREDRAW | CS_VREDRAW;
  wclass.hIconSm = 0;

  ::RegisterClassEx(&wclass);
  //DWORD gle = GetLastError();
  }

void jNativeFrameWin::CreateFrameWin(const std::string& className)
  {
  mWin.mHwnd = ::CreateWindow(
      className.c_str(), // name of window class
      "", // title-bar string
      WS_OVERLAPPEDWINDOW, // top-level window
      CW_USEDEFAULT, // default horizontal position
      CW_USEDEFAULT, // default vertical position
      CW_USEDEFAULT, // default width
      CW_USEDEFAULT, // default height
      (HWND) 0, // no owner window
      (HMENU) 0, // use class menu
      GetModuleHandle(NULL), // handle to application instance
      (LPVOID) 0); // no window-creation data
  //DWORD gle = GetLastError();
  ::SetWindowLong((HWND) mWin.mHwnd, GWL_USERDATA, (LONG) this);
  }

void jNativeFrameWin::SetSize(int width, int height)
  {
  ::SetWindowPos((HWND) mWin.mHwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
  }

long jNativeFrameWin::StartMessageLoop()
  {
  MSG msg;
  for (;;)
    {
    BOOL rc = ::GetMessage(&msg, NULL, 0, 0);
    if (rc == 0)
      {
      std::cout << "x=wm_quit: " << "\n";
      break; //WM_QUIT
      }
    if (rc == -1)
      {
      std::cout << "x=error in msgloop: " << "\n";
      break; //error.
      }
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
    }
  return (long) msg.wParam;
  }

//-------------------------------------------------------
void jNativeListBox::CreateSkeletonWindow()
  {
  jNativeWin::CreateSkeletonWindow(WC_LISTBOX);
  }

//-------------------------------------------------------
void jNativeListBox::AddString(const std::string& s)
  {
  ListBox_AddString((HWND) mWin.mHwnd, s.c_str());
  }

//-------------------------------------------------------
class jNativeMenuItem : public jMenu::MenuItem
  {
  public:
    jNativeMenuItem(jNativeFrameWin& fw, HWND hwnd, HMENU mb, unsigned int id) :
      framewin(fw), framehwnd(hwnd), menubar(mb), menuid(id)
      {
      }
    void SetMenuItemText(const std::string& newname)
      {
      MENUITEMINFO mi;
      memset(&mi, 0x00, sizeof(mi));
      mi.cbSize = sizeof(mi);
      mi.fMask = MIIM_TYPE;
      mi.fType = MFT_STRING;
      mi.dwTypeData = const_cast<char*> (newname.c_str());
      mi.cch = newname.length();

      BOOL rc = ::SetMenuItemInfo(menubar, //the menu
                                  menuid, //the menu item id
                                  FALSE, //it's an id
                                  &mi);
      rc = ::DrawMenuBar(framehwnd);
      //DWORD gle = ::GetLastError();

      framewin.UpdateMenuCommandCallBack(menuid, newname);
      }

    void SetEnabled(bool enable)
      {
      ::EnableMenuItem(menubar, menuid, (enable ? MF_ENABLED : MF_GRAYED));
//      DWORD gle = ::GetLastError();
//      std::cout << "x=enable: rc=" << rc << " gle=" << gle << std::endl;
      }

  private:
    jNativeFrameWin& framewin;
    HWND framehwnd;
    HMENU menubar;
    unsigned int menuid;
  };

typedef void (jNativeMenu::* AttachFnType)();
class jNativeMenu::Private
  {
  public:
    Private(jNativeFrameWin& w, HWND hwnd) :
      menubar(0), submenu(0), framewin(w), framehwnd(hwnd)
      {
      }

    HMENU menubar;
    HMENU submenu;
    jNativeFrameWin& framewin;
    HWND framehwnd;
    AttachFnType attach;
    static unsigned int menuid;
  };
unsigned int jNativeMenu::Private::menuid = 9000;

jNativeMenu::jNativeMenu(jNativeFrameWin& w) :
  mPrivate(*new jNativeMenu::Private(w, (HWND) w.GetWin().mHwnd))
  {
  mPrivate.menubar = ::CreateMenu();
  mPrivate.attach = &jNativeMenu::AttachMenu;
  }
jNativeMenu::~jNativeMenu()
  {
  delete &mPrivate;
  }
void jNativeMenu::AttachMenu()
  {
  ::SetMenu(mPrivate.framehwnd, mPrivate.menubar);
  mPrivate.attach = &jNativeMenu::NullAttach;
  }
void jNativeMenu::NullAttach()
  {
  //do nothing
  }
void jNativeMenu::CreateDropDown(const std::string& name)
  {
  mPrivate.submenu = ::CreatePopupMenu();
  ::AppendMenu(mPrivate.menubar, MF_STRING | MF_POPUP, (UINT_PTR) mPrivate.submenu, name.c_str());
  }
jMenu::MenuItem* jNativeMenu::AddItem(const std::string& name, MenuCallBack& fn)
  {
  mPrivate.framewin.SetMenuCommandCallBack(mPrivate.menuid, name, fn);
  ::AppendMenu(mPrivate.submenu, MF_STRING, mPrivate.menuid, name.c_str());
  mPrivate.menuid++;
  (this->*(mPrivate.attach))();
  return new jNativeMenuItem(mPrivate.framewin, mPrivate.framehwnd, mPrivate.menubar,
                             mPrivate.menuid - 1);
  }
jMenu::MenuItem* jNativeMenu::CreateMenuItem(const std::string& name, MenuCallBack& fn)
  {
  mPrivate.framewin.SetMenuCommandCallBack(mPrivate.menuid, name, fn);
  ::AppendMenu(mPrivate.menubar, MF_STRING, mPrivate.menuid, name.c_str());
  mPrivate.menuid++;
  return new jNativeMenuItem(mPrivate.framewin, mPrivate.framehwnd, mPrivate.menubar,
                             mPrivate.menuid - 1);
  }

//-------------------------------------------------------
class jNativeGraphics::Private
  {
  public:
    Private(unsigned long h) :
      hdc((HDC) h)
      {
      }

    HDC hdc;
  };

jNativeGraphics::jNativeGraphics(unsigned long hdc) :
  mPrivate(*new jNativeGraphics::Private(hdc))
  {
  }

jNativeGraphics::~jNativeGraphics()
  {
  delete &mPrivate;
  }

void jNativeGraphics::Line(int x1, int y1, int x2, int y2)
  {
  ::MoveToEx(mPrivate.hdc, x1, y1, 0);
  ::LineTo(mPrivate.hdc, x2, y2);
  }

void jNativeGraphics::FillRect(const jColor& color, const jRect& jrct)
  {
  RECT rct;
  rct.left = jrct.x;
  rct.top = jrct.y;
  rct.right = jrct.x + jrct.width;
  rct.bottom = jrct.y + jrct.height;

  COLORREF c = RGB(color.red, color.green, color.blue);

  HBRUSH b = ::CreateSolidBrush(c);
  ::FillRect(mPrivate.hdc, &rct, b);
  ::DeleteObject(b);
  }

void jNativeGraphics::Text(const std::string& txt, const jRect& jrct)
  {
  RECT rct;
  rct.left = jrct.x;
  rct.top = jrct.y;
  rct.right = jrct.x + jrct.width;
  rct.bottom = jrct.y + jrct.height;
  ::DrawText(mPrivate.hdc, txt.c_str(), txt.length(), &rct, DT_LEFT);
  }

typedef std::pair<DialogCallBack, std::string> DialogCommandInfo;
typedef std::map<short, DialogCommandInfo> DialogCommandListenerList;

class EBVFunctor
  {
  public:
    virtual void Save(char* buf) = 0;
  };

typedef std::map<short, EBVFunctor*> EditBoxVariablesList;

class EBVFunctorInt : public EBVFunctor
  {
  public:
    EBVFunctorInt(int& v) :
      Variable(&v)
      {
      }
    void Save(char* buf)
      {
      int x = atoi(buf);
      *Variable = x;
      }

    int* Variable;
  };

class EBVFunctorDouble : public EBVFunctor
  {
  public:
    EBVFunctorDouble(double& v) :
      Variable(&v)
      {
      }
    void Save(char* buf)
      {
      double x = atof(buf);
      *Variable = x;
      }

    double* Variable;
  };

static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
  jNativeDialog* This = (jNativeDialog*) ::GetWindowLong(hwnd, GWL_USERDATA);

  //  if (uMsg != 32 && uMsg != 132)
  //    std::cout << "dlg: x=" << uMsg << std::endl;

  switch (uMsg)
    {
    case WM_INITDIALOG:
      {
      jNativeDialog* This = (jNativeDialog*) lParam;
      std::cout << "dlg: x=wm_initdialog: This=" << This << std::endl;
      This->SetWindowHandle(hwnd);
      ::SetWindowLong(hwnd, GWL_USERDATA, (LONG) This);
      return 0;
      }

    case WM_DESTROY:
      std::cout << "dlg: x=wm_destroy: " << std::endl;
      return 0;

      //wparam lower 16 is the id of the command item
    case WM_COMMAND:
      {
      if (HIWORD(wParam) == 0)
        {
        This->HandleDialogEvent(LOWORD(wParam), (unsigned int) wParam, (unsigned int) lParam);
        }
      }
      return 0;
    }

  return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }

//----------------------------------------
class jNativeDialog::Private
  {
  public:
    //---------
    void init(HWND p)
      {
      //todo: check if additional structs go past buf size (see below)
      lpdt = (LPDLGTEMPLATE) calloc(4096, 1);
      lpw = (LPWORD) lpdt;
      numcontrols = 0;
      parent = p;
      }

    //from http://msdn.microsoft.com/en-us/library/ms644997%28VS.85%29.aspx
    //Each DLGITEMTEMPLATE structure in the template must be aligned on a DWORD boundary.
    ///The class and title arrays must be aligned on WORD boundaries.
    //The creation data array must be aligned on a WORD boundary.

    //from http://msdn.microsoft.com/en-us/library/ms644997%28VS.85%29.aspx
    //    0x0080  Button
    //    0x0081  Edit
    //    0x0082  Static
    //    0x0083  List box
    //    0x0084  Scroll bar
    //    0x0085  Combo box

    //---------
    void DefEdit(const std::string& text, const jRect& position)
      {
      lpw = lpDwordAlign(lpw);
      LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
      lpdit->x = position.x;
      lpdit->y = position.y;
      lpdit->cx = position.width;
      lpdit->cy = position.height;
      lpdit->id = numcontrols;
      lpdit->style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_CENTER;

      lpw = (LPWORD) (lpdit + 1); //bump lpw past DLGITEMTEMPLATE structure
      lpw = lpWordAlign(lpw);
      *lpw++ = 0xFFFF;
      *lpw++ = 0x0081; // Edit class

      lpw = lpWordAlign(lpw);
      LPWSTR lpwsz = (LPWSTR) lpw;
      //todo: the 50 is a max size of bytes for the text variable.
      int nchar = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, lpwsz, 50);
      lpw += nchar;

      lpw = lpWordAlign(lpw); // Align creation data on DWORD boundary
      *lpw++ = 0; // No creation data
      numcontrols++;
      }

    //---------
    void DefButton(const std::string& text, const jRect& position)
      {
      lpw = lpDwordAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
      LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
      lpdit->x = position.x;
      lpdit->y = position.y;
      lpdit->cx = position.width;
      lpdit->cy = position.height;
      lpdit->id = numcontrols;
      lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;

      lpw = (LPWORD) (lpdit + 1);
      lpw = lpWordAlign(lpw);
      *lpw++ = 0xFFFF;
      *lpw++ = 0x0080; // Button class

      lpw = lpWordAlign(lpw);
      LPWSTR lpwsz = (LPWSTR) lpw;
      int nchar = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, lpwsz, 50);
      lpw += nchar;

      lpw = lpWordAlign(lpw); // Align creation data on DWORD boundary
      *lpw++ = 0; // No creation data
      numcontrols++;
      }

    //---------
    void DefLabel(const std::string& text, const jRect& position)
      {
      lpw = lpDwordAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
      LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
      lpdit->x = position.x;
      lpdit->y = position.y;
      lpdit->cx = position.width;
      lpdit->cy = position.height;
      lpdit->id = numcontrols;
      lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;

      lpw = (LPWORD) (lpdit + 1);
      lpw = lpWordAlign(lpw);
      *lpw++ = 0xFFFF;
      *lpw++ = 0x0082; // Static class

      lpw = lpWordAlign(lpw);
      LPWSTR lpwsz = (LPWSTR) lpw;
      int nchar = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, lpwsz, 50);
      lpw += nchar;

      lpw = lpWordAlign(lpw);
      *lpw++ = 0; // No creation data
      numcontrols++;
      }

    //---------
    void DefDialog(const std::string& text, const jRect& position)
      {
      LPDLGTEMPLATE lpdt = (LPDLGTEMPLATE) lpw;
      lpdt->style = WS_POPUP | WS_BORDER | DS_MODALFRAME | WS_CAPTION;
      lpdt->x = position.x;
      lpdt->y = position.y;
      lpdt->cx = position.width;
      lpdt->cy = position.height;

      lpw = (LPWORD) (lpdt + 1);
      lpw = lpWordAlign(lpw);
      *lpw++ = 0; // No menu
      *lpw++ = 0; // Predefined dialog box class (by default)

      LPWSTR lpwsz = (LPWSTR) lpw;
      int nchar = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, lpwsz, 50);
      lpw += nchar;
      }

    //---------
    LPWORD lpDwordAlign(LPWORD lpIn)
      {
      ULONG ul = (ULONG) lpIn;
      ul += 3;
      ul >>= 2;
      ul <<= 2;
      return (LPWORD) ul;
      }

    //---------
    LPWORD lpWordAlign(LPWORD lpIn)
      {
      ULONG ul = (ULONG) lpIn;
      ul++;
      ul >>= 1;
      ul <<= 1;
      return (LPWORD) ul;
      }

    DialogCommandListenerList DialogCommandListeners;
    EditBoxVariablesList EditBoxVariables;
    HWND hwnd;
    HWND parent;
    LPDLGTEMPLATE lpdt;
    LPWORD lpw;
    int numcontrols;
    unsigned long returncode;
  };

//----------------------------------------
jNativeDialog::jNativeDialog() :
  mPrivate(*new jNativeDialog::Private)
  {
  }

jNativeDialog::~jNativeDialog()
  {
  delete &mPrivate;
  }

//todo: create native message box //::MessageBox(0, "Hi there", "title", MB_OK);      

void jNativeDialog::SetWindowHandle(void* hwnd)
  {
  mPrivate.hwnd = (HWND) hwnd;
  std::cout << "x=SetWindowHandle hwnd=" << mPrivate.hwnd << std::endl;
  }

bool jNativeDialog::HandleDialogEvent(unsigned short id, unsigned int parm1, unsigned int parm2)
  {
  DialogCommandListenerList::iterator pos = mPrivate.DialogCommandListeners.find(id);
  if (pos == mPrivate.DialogCommandListeners.end())
    return false;

  DialogCommandInfo info = pos->second;
  (info.first)(info.second);
  return true;
  }

//----------------------------------------
void jNativeDialog::Create(const jWin& parent, const std::string& title, const jRect& rct)
  {
  mPrivate.init((HWND) parent.mHwnd);
  mPrivate.DefDialog(title, rct);
  }

//void jNativeDialog::AddEntry(const std::string& label, double& variable, int x, int y, int labelwidth, int entrywidth, int height);
//void jNativeDialog::AddEntry(const std::string& label, std::string& variable, int x, int y, int labelwidth, int entrywidth, int height);

void jNativeDialog::AddEdit(int defaultvalue, int& variable, const jRect& rct)
  {
  mPrivate.EditBoxVariables[mPrivate.numcontrols] = new EBVFunctorInt(variable);

  std::stringstream buf;
  buf << defaultvalue;
  mPrivate.DefEdit(buf.str(), rct);
  }

void jNativeDialog::AddEdit(double defaultvalue, double& variable, const jRect& rct)
  {
  mPrivate.EditBoxVariables[mPrivate.numcontrols] = new EBVFunctorDouble(variable);

  std::stringstream buf;
  buf << defaultvalue;
  mPrivate.DefEdit(buf.str(), rct);
  }

void jNativeDialog::AddButton(const std::string& label, DialogCallBack& cmd, const jRect& rct)
  {
  mPrivate.DialogCommandListeners[mPrivate.numcontrols] = make_pair(cmd, label);
  mPrivate.DefButton(label, rct);
  }

void jNativeDialog::AddLabel(const std::string& label, const jRect& rct)
  {
  mPrivate.DefLabel(label, rct);
  }

//void jNativeDialog::SetSize(int width, int height);
void jNativeDialog::Close(unsigned long returncode)
  {
  std::cout << "x=Close hwnd=" << mPrivate.hwnd << std::endl;

  //todo: get text from edit boxes
  for (EditBoxVariablesList::iterator it = mPrivate.EditBoxVariables.begin(); it
      != mPrivate.EditBoxVariables.end(); it++)
    {
    char buf[100];
    GetDlgItemText(mPrivate.hwnd, (*it).first, buf, sizeof(buf));
    ((*it).second)->Save(buf);
    }

  ::EndDialog(mPrivate.hwnd, returncode);
  mPrivate.returncode = returncode;
  }

unsigned long jNativeDialog::Show()
  {
  mPrivate.lpdt->cdit = mPrivate.numcontrols; // Number of controls

  //mWin.mHwnd = (HWND)::CreateDialogIndirectParam( //modeless
  ::DialogBoxIndirectParam(GetModuleHandle(NULL), mPrivate.lpdt, mPrivate.parent, DialogProc,
                           (WPARAM) this);
  free(mPrivate.lpdt);
  //::SetWindowLong((HWND) mWin.mHwnd, GWL_USERDATA, (LONG) this);

  DWORD gle = GetLastError();
  std::cout << "x=gle=" << gle << std::endl;
  return mPrivate.returncode;
  }

jNativeWin.h

Synopsis
#pragma once

#include "jWin.h"
#include "jMenu.h"
#include "jRect.h"
#include "jICallBack.h"
#include <string>

//----------------------------------------
class jNativeWin
  {
  public:
    virtual ~jNativeWin(void);
    const jWin& GetWin() const
      {
      return mWin;
      }
    void ConvertToChildWindow();
    void SetParent(const jWin& parent);
    void SetSize(int x, int y, int width, int height);
    jRect GetSize();
    void Text(const std::string& s);
    void Show();
    void SetActive();
    void Redraw();
    void Close();

  protected:
    jNativeWin(void);
    void CreateSkeletonWindow(const std::string& className);
    jWin mWin;
  };

//----------------------------------------
class jNativeDialog
  {
  public:
    jNativeDialog();
    ~jNativeDialog();

    void Create(const jWin& parent, const std::string& title, const jRect& rct);
    //    void Text(const std::string& s);
    unsigned long Show();
//    void AddEntry(const std::string& label, int& variable, int x, int y, int labelwidth,
//                  int entrywidth, int height);
    void AddEdit(int defaultvalue, int& variable, const jRect& rct);
    void AddEdit(double defaultvalue, double& variable, const jRect& rct);
    void AddButton(const std::string& label, DialogCallBack& cmd, const jRect& rct);
    void AddLabel(const std::string& label, const jRect& rct);

    //void AddEntry(const std::string& label, double& variable, int x, int y, int labelwidth, int entrywidth, int height);
    //void AddEntry(const std::string& label, std::string& variable, int x, int y, int labelwidth, int entrywidth, int height);
    //void SetSize(int width, int height);
    void Close(unsigned long returncode);

    void HandleCommand(void* hwnd, short itemid); //todo: remove
    bool HandleDialogEvent(unsigned short id, unsigned int parm1, unsigned int parm2);
    void SetWindowHandle(void* hwnd);

  private:
    class Private;
    Private& mPrivate;
  };

//----------------------------------------
class jNativeFrameWin : public jNativeWin
  {
  public:
    jNativeFrameWin();

    void SetSize(int width, int height);

    void CreateSkeletonWindow(const std::string& className);
    long StartMessageLoop();

    //todo: add typedef for menu id
    void SetMenuCommandCallBack(short itemid, const std::string& name, MenuCallBack& fn);
    void UpdateMenuCommandCallBack(short itemid, const std::string& newname);
    void HandleMenuCommand(short itemid);

    void AddOnPaintCallBack(PaintCallBack& cmd) const;
    void Paint(jGraphics& g);

    //todo: add typedef for id
    //todo: rename PostEvent or AddGenericCallBack to be consistent
    void PostEvent(unsigned short id, unsigned int parm1, unsigned parm2);
    void AddGenericCallBack(unsigned short id, GenericCallBack& cmd) const;
    void HandleGenericEvent(unsigned short id, unsigned int parm1, unsigned int parm2);

  private:
    class Private;
    Private& mPrivate;
    void CreateFrameWin(const std::string& className);
    void RegisterWinClass(const std::string& className);
  };

//----------------------------------------
class jNativeListBox : public jNativeWin
  {
  public:
    void CreateSkeletonWindow();
    void AddString(const std::string& s);
  };

//----------------------------------------
class jNativeMenu
  {
  public:
    explicit jNativeMenu(jNativeFrameWin& w);
    ~jNativeMenu();
    void CreateDropDown(const std::string& name);
    jMenu::MenuItem* CreateMenuItem(const std::string& name, MenuCallBack& fn);
    jMenu::MenuItem* AddItem(const std::string& name, MenuCallBack& fn);

  private:
    class Private;
    Private& mPrivate;
    void AttachMenu();
    void NullAttach();
  };

//----------------------------------------
class jColor;
class jNativeGraphics
  {
  public:
    explicit jNativeGraphics(unsigned long hdc);
    ~jNativeGraphics();

    void Line(int x1, int y1, int x2, int y2);
    void FillRect(const jColor& color, const jRect& rct);
    void Text(const std::string& txt, const jRect& rct);

  private:
    class Private;
    Private& mPrivate;
  };

jRect.h

Synopsis
#pragma once

class jRect
  {
  public:
    int x;
    int y;
    int width;
    int height;
  };

jTypeList.h

Synopsis
#pragma once

namespace TL
  {
  struct NullType
    {
      enum
        {
        Length = 0
        };
    };

  template <typename T0, typename T1> struct TypeList
    {
      typedef T0 Head;
      typedef T1 Tail;

      enum
        {
        Length = 1 + Tail::Length
        };
    };

#define TYPELIST0()           TL::NullType
#define TYPELIST1(T1)         TL::TypeList<T1, TL::NullType >
#define TYPELIST2(T1, T2)     TL::TypeList<T1, TYPELIST1(T2) >
#define TYPELIST3(T1, T2, T3) TL::TypeList<T1, TYPELIST2(T2, T3) >

  //--- Length ------
  template <typename TList> struct Length;
  template <> struct Length<NullType>
    {
      enum
        {
        Value = 0
        };
    };
  template <typename T0, typename T1> struct Length<TypeList<T0, T1> >
    {
      enum
        {
        Value = 1 + Length<T1>::Value
        };
    };

  //--- TypeAt ------
  template <class TList, unsigned int index, class OutOfBound = NullType> struct TypeAt;

  template <class THead, class TTail, class OutOfBound> struct TypeAt<TypeList<THead, TTail> , 0,
      OutOfBound>
    {
      typedef THead Type;
    };

  template <class THead, class TTail, unsigned int i, class OutOfBound> struct TypeAt<TypeList<
      THead, TTail> , i, OutOfBound>
    {
      typedef typename TypeAt<TTail, i - 1>::Type Type;
    };

  template <unsigned int i, class OutOfBound> struct TypeAt<NullType, i, OutOfBound>
    {
      typedef OutOfBound Type;
    };

  }

jWin.h

Synopsis
#pragma once

class jWin
  {
  public:
    void SetWin(void* hwnd)
      {
      mHwnd = hwnd;
      }
  private:
    friend class jNativeFrameWin;
    friend class jNativeWin;
    friend class jNativeListBox;
    friend class jNativeMenu;
    friend class jNativeDialog;
    void* mHwnd;
  };

jWinComponent.h

Synopsis
#pragma once

class jWin;
class jWinComponent
  {
  public:
    virtual ~jWinComponent()
      {
      }
    virtual void SetOwnerTo(const jWin& owner) = 0;
    virtual void SetSize(int x, int y, int width, int height) = 0;
  };






Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001-2010