<commit_before>///
/// @file  CpuInfo.cpp
/// @brief Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <string>
#include <vector>

#if defined(_WIN32)
#include <windows.h>
#endif

#if !defined(_WIN32)

#include <array>
#include <cstdio>
#include <memory>

using namespace std;

namespace {

/// Execute command and return its stdout.
/// @see https://stackoverflow.com/a/478960/363778
///
string exec(string cmd)
{
  shared_ptr<FILE> file(popen(cmd.c_str(), "r"), pclose);
  string stdout;

  if (file)
  {
    array<char, 128> buffer;

    while (!feof(file.get()))
    {
      if (fgets(buffer.data(), buffer.size(), file.get()))
        stdout += buffer.data();
    }
  }

  return stdout;
}

/// Find cacheId in string and return its size.
/// Example: "L1_CACHE_SIZE=32768;"
///
size_t getCacheSize(string stdout, string cacheId)
{
  size_t pos = stdout.find(cacheId);
  size_t cacheSize = 0;
  string cacheStr;

  if (pos != string::npos)
  {
    size_t n1 = stdout.find_first_of('=', pos) + 1;
    size_t n2 = stdout.find_first_not_of("0123456789", n1);

    if (n1 != string::npos &&
        n2 != string::npos)
    {
      size_t length = n2 - n1;
      cacheStr = stdout.substr(n1, length);

      if (!cacheStr.empty())
        cacheSize = stol(cacheStr);

      if (cacheStr[n2] == 'K')
        cacheSize *= 1024;
      if (cacheStr[n2] == 'M')
        cacheSize *= 1024 * 1024;
      if (cacheStr[n2] == 'G')
        cacheSize *= 1024 * 1024 * 1024;
    }
  }

  return cacheSize;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    l3CacheSize_(0)
{
  initCache();
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

size_t CpuInfo::l3CacheSize() const
{
  return l3CacheSize_;
}

#if defined(_WIN32)

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

void CpuInfo::initCache()
{
  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (glpi)
  {
    DWORD bytes = 0;
    glpi(0, &bytes);
    size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);
    glpi(info.data(), &bytes);

    for (size_t i = 0; i < size; i++)
    {
      if (info[i].Relationship == RelationCache)
      {
        if (info[i].Cache.Level == 1)
          l1CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 2)
          l2CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 3)
          l3CacheSize_ = info[i].Cache.Size;
      }
    }
  }
}

#else

void CpuInfo::initCache()
{
  // Posix shell script for UNIX like OSes
  // The script tries to get the cache size using 3 different approaches:
  // 1) getconf LEVEL*_CACHE_SIZE
  // 2) sysctl hw.l*cachesize
  // 3) cat /sys/devices/system/cpu/cpu0/cache/index*/size
  //
  const string cacheSizeScript = R"(
      command -v getconf >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          L1_CACHE_SIZE=$(getconf LEVEL1_DCACHE_SIZE 2>/dev/null);
          L2_CACHE_SIZE=$(getconf LEVEL2_CACHE_SIZE 2>/dev/null);
          L3_CACHE_SIZE=$(getconf LEVEL3_CACHE_SIZE 2>/dev/null);
      fi;

      command -v sysctl >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          if [ "x$L1_CACHE_SIZE" = "x" ] || \
             [ "$L1_CACHE_SIZE" = "0" ];
          then
              L1_CACHE_SIZE=$(sysctl -n hw.l1dcachesize 2>/dev/null);
          fi;

          if [ "x$L2_CACHE_SIZE" = "x" ] || \
             [ "$L2_CACHE_SIZE" = "0" ];
          then
              L2_CACHE_SIZE=$(sysctl -n hw.l2cachesize 2>/dev/null);
          fi;

          if [ "x$L3_CACHE_SIZE" = "x" ] || \
             [ "$L3_CACHE_SIZE" = "0" ];
          then
              L3_CACHE_SIZE=$(sysctl -n hw.l3cachesize 2>/dev/null);
          fi;
      fi;

      if [ "x$L1_CACHE_SIZE" = "x" ] || \
         [ "$L1_CACHE_SIZE" = "0" ];
      then
          L1_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index0/size 2>/dev/null);
      fi;

      if [ "x$L2_CACHE_SIZE" = "x" ] || \
         [ "$L2_CACHE_SIZE" = "0" ];
      then
          L2_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index2/size 2>/dev/null);
      fi;

      if [ "x$L3_CACHE_SIZE" = "x" ] || \
         [ "$L3_CACHE_SIZE" = "0" ];
      then
          L3_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index3/size 2>/dev/null);
      fi;

      echo "L1_CACHE_SIZE=$L1_CACHE_SIZE; \
            L2_CACHE_SIZE=$L2_CACHE_SIZE; \
            L3_CACHE_SIZE=$L3_CACHE_SIZE;"
  )";

  string stdout = exec(cacheSizeScript);

  l1CacheSize_ = getCacheSize(stdout, "L1_CACHE_SIZE");
  l2CacheSize_ = getCacheSize(stdout, "L2_CACHE_SIZE");
  l3CacheSize_ = getCacheSize(stdout, "L3_CACHE_SIZE");
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<commit_msg>Fix last character issue<commit_after>///
/// @file  CpuInfo.cpp
/// @brief Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <string>
#include <vector>

#if defined(_WIN32)
#include <windows.h>
#endif

#if !defined(_WIN32)

#include <array>
#include <cstdio>
#include <memory>

using namespace std;

namespace {

/// Execute command and return its stdout.
/// @see https://stackoverflow.com/a/478960/363778
///
string exec(string cmd)
{
  shared_ptr<FILE> file(popen(cmd.c_str(), "r"), pclose);
  string stdout;

  if (file)
  {
    array<char, 128> buffer;

    while (!feof(file.get()))
    {
      if (fgets(buffer.data(), buffer.size(), file.get()))
        stdout += buffer.data();
    }
  }

  return stdout;
}

/// Find cacheId in string and return its size.
/// Example: "L1_CACHE_SIZE=32768;"
///
size_t getCacheSize(string stdout, string cacheId)
{
  size_t pos = stdout.find(cacheId);
  size_t cacheSize = 0;
  string cacheStr;

  if (pos != string::npos)
  {
    size_t n1 = stdout.find_first_of('=', pos) + 1;
    size_t n2 = stdout.find_first_not_of("0123456789", n1);

    if (n1 != string::npos &&
        n2 != string::npos)
    {
      size_t length = n2 - n1;
      cacheStr = stdout.substr(n1, length);

      if (!cacheStr.empty())
        cacheSize = stol(cacheStr);

      if (stdout[n2] == 'K')
        cacheSize *= 1024;
      if (stdout[n2] == 'M')
        cacheSize *= 1024 * 1024;
      if (stdout[n2] == 'G')
        cacheSize *= 1024 * 1024 * 1024;
    }
  }

  return cacheSize;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    l3CacheSize_(0)
{
  initCache();
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

size_t CpuInfo::l3CacheSize() const
{
  return l3CacheSize_;
}

#if defined(_WIN32)

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

void CpuInfo::initCache()
{
  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (glpi)
  {
    DWORD bytes = 0;
    glpi(0, &bytes);
    size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);
    glpi(info.data(), &bytes);

    for (size_t i = 0; i < size; i++)
    {
      if (info[i].Relationship == RelationCache)
      {
        if (info[i].Cache.Level == 1)
          l1CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 2)
          l2CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 3)
          l3CacheSize_ = info[i].Cache.Size;
      }
    }
  }
}

#else

void CpuInfo::initCache()
{
  // Posix shell script for UNIX like OSes
  // The script tries to get the cache size using 3 different approaches:
  // 1) getconf LEVEL*_CACHE_SIZE
  // 2) sysctl hw.l*cachesize
  // 3) cat /sys/devices/system/cpu/cpu0/cache/index*/size
  //
  const string cacheSizeScript = R"(
      command -v getconf >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          L1_CACHE_SIZE=$(getconf LEVEL1_DCACHE_SIZE 2>/dev/null);
          L2_CACHE_SIZE=$(getconf LEVEL2_CACHE_SIZE 2>/dev/null);
          L3_CACHE_SIZE=$(getconf LEVEL3_CACHE_SIZE 2>/dev/null);
      fi;

      command -v sysctl >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          if [ "x$L1_CACHE_SIZE" = "x" ] || \
             [ "$L1_CACHE_SIZE" = "0" ];
          then
              L1_CACHE_SIZE=$(sysctl -n hw.l1dcachesize 2>/dev/null);
          fi;

          if [ "x$L2_CACHE_SIZE" = "x" ] || \
             [ "$L2_CACHE_SIZE" = "0" ];
          then
              L2_CACHE_SIZE=$(sysctl -n hw.l2cachesize 2>/dev/null);
          fi;

          if [ "x$L3_CACHE_SIZE" = "x" ] || \
             [ "$L3_CACHE_SIZE" = "0" ];
          then
              L3_CACHE_SIZE=$(sysctl -n hw.l3cachesize 2>/dev/null);
          fi;
      fi;

      if [ "x$L1_CACHE_SIZE" = "x" ] || \
         [ "$L1_CACHE_SIZE" = "0" ];
      then
          L1_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index0/size 2>/dev/null);
      fi;

      if [ "x$L2_CACHE_SIZE" = "x" ] || \
         [ "$L2_CACHE_SIZE" = "0" ];
      then
          L2_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index2/size 2>/dev/null);
      fi;

      if [ "x$L3_CACHE_SIZE" = "x" ] || \
         [ "$L3_CACHE_SIZE" = "0" ];
      then
          L3_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index3/size 2>/dev/null);
      fi;

      echo "L1_CACHE_SIZE=$L1_CACHE_SIZE; \
            L2_CACHE_SIZE=$L2_CACHE_SIZE; \
            L3_CACHE_SIZE=$L3_CACHE_SIZE;"
  )";

  string stdout = exec(cacheSizeScript);

  l1CacheSize_ = getCacheSize(stdout, "L1_CACHE_SIZE");
  l2CacheSize_ = getCacheSize(stdout, "L2_CACHE_SIZE");
  l3CacheSize_ = getCacheSize(stdout, "L3_CACHE_SIZE");
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<|endoftext|>


<commit_before>#include "api/plugin_instance.h"
#include "core/core.h"
#include "core/log.h"
#include "core/math.h"
#include "core/plugin_handler.h"
#include "session/session.h"
#include "settings.h"
//#include <imgui.h>
#include "ui/imgui_setup.h"
#include "ui/menu.h"
#include "ui/dialogs.h"
#include "ui/cursor.h"
#include "ui/ui_render.h"
#include "ui/ui_statusbar.h"
#include "input/input_state.h"

#include <bgfx.h>
#include <bgfxplatform.h>
#include <stdio.h>
#include <stdlib.h>
#include <bx/timer.h>

#include <remotery.h>
#include <assert.h>

#include <foundation/environment.h>
#include <foundation/fs.h>
#include <foundation/string.h>
#include <foundation/path.h>

// TODO: Fix me

int Window_buildPluginMenu(PluginData** plugins, int count);
void Window_addMenu(const char* name, PDMenuItem* items, uint32_t idOffset);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct Context
{
    InputState inputState;
    int width;
    int height;
    uint64_t time;
    Session* session;   // one session right now
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Context s_context;
//Remotery* s_remotery;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const char* s_plugins[] =
{
    "sourcecode_plugin",
    "disassembly_plugin",
    "locals_plugin",
    "callstack_plugin",
    "registers_plugin",
    "breakpoints_plugin",
    "hex_memory_plugin",
    "console_plugin",
    "c64_vice_plugin",
#ifdef PRODBG_MAC
    "lldb_plugin",
#endif
#ifdef PRODBG_WIN
    "dbgeng_plugin",
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loadLayout(Session* session, float width, float height)
{
    // TODO: Fix convesion

    if (Session_loadLayout(session, "data/current_layout.json", (int)width, (int)height))
        return;

    if (Session_loadLayout(session, "data/default_layout.json", (int)width, (int)height))
        return;

    Session_createDockingGrid(session, (int)width, (int)height);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

uint32_t findMenuIdRange(PDMenu* menu)
{
    uint32_t idStart = uint32_t(~0);
    uint32_t idEnd = 0;

    while (menu->name)
    {
        PDMenuItem* menuItems = menu->items;

        while (menuItems->name)
        {
            const uint16_t id = menuItems->id;

            if (id > idEnd)
                idEnd = id;

            if (id < idStart)
                idStart = id;

            menuItems++;
        }

        menu++;
    }

    return (idEnd << 16) | idStart;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void createMenusForPlugins()
{
    int count = 0;

    PluginData** plugins = PluginHandler_getBackendPlugins(&count);

    uint32_t menuIdStart = PRODBG_MENU_PLUGINS_START;

    for (int i = 0; i < count; ++i)
    {
        PluginData* pluginData = plugins[i];

        PDBackendPlugin* plugin = (PDBackendPlugin*)pluginData->plugin;

        if (!plugin)
            continue;

        if (!plugin->registerMenu)
            continue;

        PDMenu* menus = plugin->registerMenu();
        uint32_t menuRange = findMenuIdRange(menus);

        while (menus->name)
        {
            Window_addMenu(menus->name, menus->items, menuIdStart);
            menus++;
        }

        pluginData->menuStart = menuIdStart;
        pluginData->menuEnd = menuIdStart + (menuRange >> 16);

        menuIdStart += (menuRange >> 16);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bool findDataDirectory()
{
	// check if the data dir is directly here

	if (fs_is_directory("data"))
		return true;

	const char* exe_file_path = environment_executable_path();
	const char* exe_path = path_directory_name(exe_file_path );

	char* path = string_clone(exe_path);

	// search max 10 levels up

	for (int i = 0; i < 10; ++i)
	{
	#if defined(PRODBG_WIN)
		path = string_append(path, "\\..");
	#else
		path = string_append(path, "/..");
	#endif

		environment_set_current_working_directory(path);

		if (fs_is_directory("data"))
			return true;
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_create(void* window, int width, int height)
{
    Context* context = &s_context;
    //Rect settingsRect;
    //

	Core_init();

	findDataDirectory();

    context->session = Session_create();
    context->time = bx::getHPCounter();

#if PRODBG_USING_DOCKING
    loadLayout(context->session, (float)width, (float)(height - g_statusBarSize));
#endif

    /*
       if (RMT_ERROR_NONE != rmt_CreateGlobalInstance(&s_remotery))
       {
        pd_error("Unable to setup Remotery");
        return;
       }
     */

    //Settings_getWindowRect(&settingsRect);
    //width = settingsRect.width;
    //height = settingsRect.height;

    (void)window;

    for (uint32_t i = 0; i < sizeof_array(s_plugins); ++i)
    {
        PluginHandler_addPlugin(OBJECT_DIR, s_plugins[i]);
    }

#if BX_PLATFORM_OSX
    bgfx::osxSetNSWindow(window);
#elif BX_PLATFORM_WINDOWS
    bgfx::winSetHwnd((HWND)window);
#else
    //bgfx::winSetHwnd(0);
#endif

    bgfx::init();
    bgfx::reset(width, height);
    bgfx::setViewSeq(0, true);

    context->width = width;
    context->height = height;

    IMGUI_setup(width, height);

    Cursor_init();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void updateDock(Context* context)
{
    UIDockingGrid* grid = Session_getDockingGrid(context->session);
    const InputState* inputState = &context->inputState;

    switch (UIDock_getSizingState(grid))
    {
        case UIDockSizerDir_None:
        {
            Cunsor_setType(CursorType_Default);
            break;
        }

        case UIDockSizerDir_Horz:
        {
            Cunsor_setType(CursorType_SizeHorizontal);
            break;
        }

        case UIDockSizerDir_Vert:
        {
            Cunsor_setType(CursorType_SizeVertical);
            break;
        }

        case UIDockSizerDir_Both:
        {
            Cunsor_setType(CursorType_SizeAll);
            break;
        }
    }

    UIDock_update(grid, inputState);
    UIDock_renderSizers(grid);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_update()
{
    Context* context = &s_context;

    rmt_ScopedCPUSample(ProDBG_update);

    bgfx::setViewRect(0, 0, 0, (uint16_t)context->width, (uint16_t)context->height);
    bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x101010ff, 1.0f, 0);
    bgfx::submit(0);

    uint64_t currentTime = bx::getHPCounter();
    uint64_t deltaTick = currentTime - context->time;
    context->time = currentTime;

    float deltaTimeMs = (float)(((double)deltaTick) / (double)bx::getHPFrequency());

#if PRODBG_USING_DOCKING
    updateDock(context);
#endif
    {
        rmt_ScopedCPUSample(IMGUI_preUpdate);
        IMGUI_preUpdate(&context->inputState, deltaTimeMs);
    }

    // TODO: Support multiple sessions

    {
        rmt_ScopedCPUSample(Session_update);
        Session_update(context->session);
    }

    UIStatusBar_render();

    //renderTest();

    /*

       bool show = true;

       ImGui::Begin("ImGui Test", &show, ImVec2(550, 480), true, ImGuiWindowFlags_ShowBorders);

       if (ImGui::Button("Test0r testing!"))
       {
        printf("test\n");
       }

       ImGui::End();
     */

    {
        rmt_ScopedCPUSample(IMGUI_postUpdate);
        IMGUI_postUpdate();
    }

    {
        rmt_ScopedCPUSample(bgfx_frame);
        bgfx::frame();
    }
}

// Temprory test for monkey

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setWindowSize(int width, int height)
{
    Context* context = &s_context;

    context->width = width;
    context->height = height;

    bgfx::reset(width, height);
    IMGUI_updateSize(width, height);

#if PRODBG_USING_DOCKING
    UIDock_updateSize(Session_getDockingGrid(context->session), width, height - (int)g_statusBarSize);
#endif

    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_applicationLaunched()
{
    int pluginCount = 0;
    Window_buildPluginMenu(PluginHandler_getViewPlugins(&pluginCount), pluginCount);
    createMenusForPlugins();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_destroy()
{
    Context* context = &s_context;

    //rmt_DestroyGlobalInstance(s_remotery);

    UIDock_saveLayout(Session_getDockingGrid(context->session),
                      "data/current_layout.json", (float)context->width, (float)(context->height - g_statusBarSize));

	Session_destroy(context->session);

    Settings_save();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_timedUpdate()
{
    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void onLoadRunExec(Session* session, const char* filename)
{
    PluginData* pluginData = PluginHandler_findPlugin(0, "lldb_plugin", "LLDB Mac", true);

    if (!pluginData)
    {
        pd_error("Unable to find LLDB Mac backend\n");
        return;
    }

    Session_startLocal(session, (PDBackendPlugin*)pluginData->plugin, filename);

    // Temp test
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, "t2-output/macosx-clang-debug-default/ProDBG.app/Contents/MacOS/prodbg");
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, OBJECT_DIR "/crashing_native");
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events

void ProDBG_event(int eventId)
{
    Context* context = &s_context;

    int count;

    PluginData** pluginsData = PluginHandler_getViewPlugins(&count);

    pd_info("eventId 0x%x\n", eventId);

    Vec2 mousePos = context->inputState.mousePos;

#if PRODBG_USING_DOCKING
    if (eventId & PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT)
    {
        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitHorizontal(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    if (eventId & PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT)
    {

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

#endif

    // TODO: This code really needs to be made more robust.

    if (eventId >= PRODBG_MENU_PLUGIN_START && eventId < PRODBG_MENU_PLUGIN_START + 9)
    {
        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId - PRODBG_MENU_PLUGIN_START]);

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, 0, 0);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    switch (eventId)
    {
        case PRODBG_MENU_FILE_OPEN_AND_RUN_EXE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                onLoadRunExec(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_FILE_OPEN_SOURCE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                Session_loadSourceFile(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_DEBUG_START:
        {
            Session_action(context->session, PDAction_run);
            printf("run....\n");
            break;
        }

        case PRODBG_MENU_DEBUG_ATTACH_TO_REMOTE:
        {
            Session_startRemote(context->session, "127.0.0.1", 1340);
            break;
        }

        case PRODBG_MENU_DEBUG_TOGGLE_BREAKPOINT:
        {
            Session_toggleBreakpointCurrentLine(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_OVER:
        {
            Session_stepOver(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_IN:
        {
            Session_stepIn(context->session);
            break;
        }
    }

    if (eventId >= PRODBG_MENU_PLUGINS_START)
    {
        Session_onMenu(context->session, eventId);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_scroll(const PDMouseWheelEvent& wheelEvent)
{
    Context* context = &s_context;
    context->inputState.scrollEvent = wheelEvent;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMousePos(float x, float y)
{
    Context* context = &s_context;

    context->inputState.mousePos.x = x;
    context->inputState.mousePos.y = y;

    IMGUI_setInputState(&context->inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMouseState(int button, int state)
{
    Context* context = &s_context;
    (void)button;

    InputState* inputState = &context->inputState;

    // TODO: Proper mouse support

    inputState->mouseDown[0] = !!state;

    IMGUI_setInputState(inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyDown(int key, int modifier)
{
    IMGUI_setKeyDown(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyUp(int key, int modifier)
{
    IMGUI_setKeyUp(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_addChar(unsigned short c)
{
    IMGUI_addInputCharacter(c);
}

<commit_msg>Replaced bx/timer with foundation/time<commit_after>#include "api/plugin_instance.h"
#include "core/core.h"
#include "core/log.h"
#include "core/math.h"
#include "core/plugin_handler.h"
#include "session/session.h"
#include "settings.h"
//#include <imgui.h>
#include "ui/imgui_setup.h"
#include "ui/menu.h"
#include "ui/dialogs.h"
#include "ui/cursor.h"
#include "ui/ui_render.h"
#include "ui/ui_statusbar.h"
#include "input/input_state.h"

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

#include <remotery.h>
#include <assert.h>

#include <foundation/environment.h>
#include <foundation/fs.h>
#include <foundation/string.h>
#include <foundation/path.h>
#include <foundation/time.h>

// TODO: Fix me

int Window_buildPluginMenu(PluginData** plugins, int count);
void Window_addMenu(const char* name, PDMenuItem* items, uint32_t idOffset);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct Context
{
    InputState inputState;
    int width;
    int height;
    uint64_t time;
    Session* session;   // one session right now
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Context s_context;
//Remotery* s_remotery;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const char* s_plugins[] =
{
    "sourcecode_plugin",
    "disassembly_plugin",
    "locals_plugin",
    "callstack_plugin",
    "registers_plugin",
    "breakpoints_plugin",
    "hex_memory_plugin",
    "console_plugin",
    "c64_vice_plugin",
#ifdef PRODBG_MAC
    "lldb_plugin",
#endif
#ifdef PRODBG_WIN
    "dbgeng_plugin",
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loadLayout(Session* session, float width, float height)
{
    // TODO: Fix convesion

    if (Session_loadLayout(session, "data/current_layout.json", (int)width, (int)height))
        return;

    if (Session_loadLayout(session, "data/default_layout.json", (int)width, (int)height))
        return;

    Session_createDockingGrid(session, (int)width, (int)height);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

uint32_t findMenuIdRange(PDMenu* menu)
{
    uint32_t idStart = uint32_t(~0);
    uint32_t idEnd = 0;

    while (menu->name)
    {
        PDMenuItem* menuItems = menu->items;

        while (menuItems->name)
        {
            const uint16_t id = menuItems->id;

            if (id > idEnd)
                idEnd = id;

            if (id < idStart)
                idStart = id;

            menuItems++;
        }

        menu++;
    }

    return (idEnd << 16) | idStart;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void createMenusForPlugins()
{
    int count = 0;

    PluginData** plugins = PluginHandler_getBackendPlugins(&count);

    uint32_t menuIdStart = PRODBG_MENU_PLUGINS_START;

    for (int i = 0; i < count; ++i)
    {
        PluginData* pluginData = plugins[i];

        PDBackendPlugin* plugin = (PDBackendPlugin*)pluginData->plugin;

        if (!plugin)
            continue;

        if (!plugin->registerMenu)
            continue;

        PDMenu* menus = plugin->registerMenu();
        uint32_t menuRange = findMenuIdRange(menus);

        while (menus->name)
        {
            Window_addMenu(menus->name, menus->items, menuIdStart);
            menus++;
        }

        pluginData->menuStart = menuIdStart;
        pluginData->menuEnd = menuIdStart + (menuRange >> 16);

        menuIdStart += (menuRange >> 16);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bool findDataDirectory()
{
	// check if the data dir is directly here

	if (fs_is_directory("data"))
		return true;

	const char* exe_file_path = environment_executable_path();
	const char* exe_path = path_directory_name(exe_file_path );

	char* path = string_clone(exe_path);

	// search max 10 levels up

	for (int i = 0; i < 10; ++i)
	{
	#if defined(PRODBG_WIN)
		path = string_append(path, "\\..");
	#else
		path = string_append(path, "/..");
	#endif

		environment_set_current_working_directory(path);

		if (fs_is_directory("data"))
			return true;
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_create(void* window, int width, int height)
{
    Context* context = &s_context;
    //Rect settingsRect;
    //

	Core_init();

	findDataDirectory();

    context->session = Session_create();
    context->time = time_current();

#if PRODBG_USING_DOCKING
    loadLayout(context->session, (float)width, (float)(height - g_statusBarSize));
#endif

    /*
       if (RMT_ERROR_NONE != rmt_CreateGlobalInstance(&s_remotery))
       {
        pd_error("Unable to setup Remotery");
        return;
       }
     */

    //Settings_getWindowRect(&settingsRect);
    //width = settingsRect.width;
    //height = settingsRect.height;

    (void)window;

    for (uint32_t i = 0; i < sizeof_array(s_plugins); ++i)
    {
        PluginHandler_addPlugin(OBJECT_DIR, s_plugins[i]);
    }

#if BX_PLATFORM_OSX
    bgfx::osxSetNSWindow(window);
#elif BX_PLATFORM_WINDOWS
    bgfx::winSetHwnd((HWND)window);
#else
    //bgfx::winSetHwnd(0);
#endif

    bgfx::init();
    bgfx::reset(width, height);
    bgfx::setViewSeq(0, true);

    context->width = width;
    context->height = height;

    IMGUI_setup(width, height);

    Cursor_init();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void updateDock(Context* context)
{
    UIDockingGrid* grid = Session_getDockingGrid(context->session);
    const InputState* inputState = &context->inputState;

    switch (UIDock_getSizingState(grid))
    {
        case UIDockSizerDir_None:
        {
            Cunsor_setType(CursorType_Default);
            break;
        }

        case UIDockSizerDir_Horz:
        {
            Cunsor_setType(CursorType_SizeHorizontal);
            break;
        }

        case UIDockSizerDir_Vert:
        {
            Cunsor_setType(CursorType_SizeVertical);
            break;
        }

        case UIDockSizerDir_Both:
        {
            Cunsor_setType(CursorType_SizeAll);
            break;
        }
    }

    UIDock_update(grid, inputState);
    UIDock_renderSizers(grid);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_update()
{
    Context* context = &s_context;

    rmt_ScopedCPUSample(ProDBG_update);

    bgfx::setViewRect(0, 0, 0, (uint16_t)context->width, (uint16_t)context->height);
    bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x101010ff, 1.0f, 0);
    bgfx::submit(0);

    uint64_t currentTime = time_current();

	float dt = time_elapsed(context->time);

    context->time = currentTime;

#if PRODBG_USING_DOCKING
    updateDock(context);
#endif
    {
        rmt_ScopedCPUSample(IMGUI_preUpdate);
        IMGUI_preUpdate(&context->inputState, dt);
    }

    // TODO: Support multiple sessions

    {
        rmt_ScopedCPUSample(Session_update);
        Session_update(context->session);
    }

    UIStatusBar_render();

    //renderTest();

    /*

       bool show = true;

       ImGui::Begin("ImGui Test", &show, ImVec2(550, 480), true, ImGuiWindowFlags_ShowBorders);

       if (ImGui::Button("Test0r testing!"))
       {
        printf("test\n");
       }

       ImGui::End();
     */

    {
        rmt_ScopedCPUSample(IMGUI_postUpdate);
        IMGUI_postUpdate();
    }

    {
        rmt_ScopedCPUSample(bgfx_frame);
        bgfx::frame();
    }
}

// Temprory test for monkey

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setWindowSize(int width, int height)
{
    Context* context = &s_context;

    context->width = width;
    context->height = height;

    bgfx::reset(width, height);
    IMGUI_updateSize(width, height);

#if PRODBG_USING_DOCKING
    UIDock_updateSize(Session_getDockingGrid(context->session), width, height - (int)g_statusBarSize);
#endif

    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_applicationLaunched()
{
    int pluginCount = 0;
    Window_buildPluginMenu(PluginHandler_getViewPlugins(&pluginCount), pluginCount);
    createMenusForPlugins();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_destroy()
{
    Context* context = &s_context;

    //rmt_DestroyGlobalInstance(s_remotery);

    UIDock_saveLayout(Session_getDockingGrid(context->session),
                      "data/current_layout.json", (float)context->width, (float)(context->height - g_statusBarSize));

	Session_destroy(context->session);

    Settings_save();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_timedUpdate()
{
    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void onLoadRunExec(Session* session, const char* filename)
{
    PluginData* pluginData = PluginHandler_findPlugin(0, "lldb_plugin", "LLDB Mac", true);

    if (!pluginData)
    {
        pd_error("Unable to find LLDB Mac backend\n");
        return;
    }

    Session_startLocal(session, (PDBackendPlugin*)pluginData->plugin, filename);

    // Temp test
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, "t2-output/macosx-clang-debug-default/ProDBG.app/Contents/MacOS/prodbg");
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, OBJECT_DIR "/crashing_native");
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events

void ProDBG_event(int eventId)
{
    Context* context = &s_context;

    int count;

    PluginData** pluginsData = PluginHandler_getViewPlugins(&count);

    pd_info("eventId 0x%x\n", eventId);

    Vec2 mousePos = context->inputState.mousePos;

#if PRODBG_USING_DOCKING
    if (eventId & PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT)
    {
        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitHorizontal(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    if (eventId & PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT)
    {

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

#endif

    // TODO: This code really needs to be made more robust.

    if (eventId >= PRODBG_MENU_PLUGIN_START && eventId < PRODBG_MENU_PLUGIN_START + 9)
    {
        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId - PRODBG_MENU_PLUGIN_START]);

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, 0, 0);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    switch (eventId)
    {
        case PRODBG_MENU_FILE_OPEN_AND_RUN_EXE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                onLoadRunExec(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_FILE_OPEN_SOURCE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                Session_loadSourceFile(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_DEBUG_START:
        {
            Session_action(context->session, PDAction_run);
            printf("run....\n");
            break;
        }

        case PRODBG_MENU_DEBUG_ATTACH_TO_REMOTE:
        {
            Session_startRemote(context->session, "127.0.0.1", 1340);
            break;
        }

        case PRODBG_MENU_DEBUG_TOGGLE_BREAKPOINT:
        {
            Session_toggleBreakpointCurrentLine(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_OVER:
        {
            Session_stepOver(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_IN:
        {
            Session_stepIn(context->session);
            break;
        }
    }

    if (eventId >= PRODBG_MENU_PLUGINS_START)
    {
        Session_onMenu(context->session, eventId);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_scroll(const PDMouseWheelEvent& wheelEvent)
{
    Context* context = &s_context;
    context->inputState.scrollEvent = wheelEvent;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMousePos(float x, float y)
{
    Context* context = &s_context;

    context->inputState.mousePos.x = x;
    context->inputState.mousePos.y = y;

    IMGUI_setInputState(&context->inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMouseState(int button, int state)
{
    Context* context = &s_context;
    (void)button;

    InputState* inputState = &context->inputState;

    // TODO: Proper mouse support

    inputState->mouseDown[0] = !!state;

    IMGUI_setInputState(inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyDown(int key, int modifier)
{
    IMGUI_setKeyDown(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyUp(int key, int modifier)
{
    IMGUI_setKeyUp(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_addChar(unsigned short c)
{
    IMGUI_addInputCharacter(c);
}

<|endoftext|>


<commit_before>#include "buffers.h"
#include "strutil.h"
#include "log.h"

void processQueue(ByteQueue* queue, bool (*callback)(uint8_t*)) {
    uint8_t snapshot[queue_length(queue)];
    queue_snapshot(queue, snapshot);
    if(callback == NULL) {
        debug("Callback is NULL (%p) -- unable to handle queue at %p\r\n",
                callback, queue);
        return;
    }

    if(callback(snapshot)) {
        queue_init(queue);
    } else if(queue_full(queue)) {
        debug("Incoming write is too long\r\n");
        queue_init(queue);
    } else if(strnchr((char*)snapshot, queue_length(queue) - 1, '\0') != NULL) {
        debug("Incoming buffered write corrupted (%s) -- clearing buffer\r\n",
                snapshot);
        queue_init(queue);
    }
}
<commit_msg>Don't walk off the end of a snapshot if interrupt is still adding to queue.<commit_after>#include "buffers.h"
#include "strutil.h"
#include "log.h"

void processQueue(ByteQueue* queue, bool (*callback)(uint8_t*)) {
    uint8_t snapshot[queue_length(queue)];
    queue_snapshot(queue, snapshot);
    if(callback == NULL) {
        debug("Callback is NULL (%p) -- unable to handle queue at %p\r\n",
                callback, queue);
        return;
    }

    if(callback(snapshot)) {
        queue_init(queue);
    } else if(queue_full(queue)) {
        debug("Incoming write is too long\r\n");
        queue_init(queue);
    } else if(strnchr((char*)snapshot, sizeof(snapshot) - 1, '\0') != NULL) {
        debug("Incoming buffered write corrupted (%s) -- clearing buffer\r\n",
                snapshot);
        queue_init(queue);
    }
}
<|endoftext|>


<commit_before>#include "canread.h"
#include <stdlib.h>
#include "log.h"

/* Private: Serialize the root JSON object to a string (ending with a newline)
 * and send it to the listener.
 *
 * root - The JSON object to send.
 * listener - The listener device to send on.
 */
void sendJSON(cJSON* root, Listener* listener) {
    char* message = cJSON_PrintUnformatted(root);
    sendMessage(listener, (uint8_t*) message, strlen(message));
    cJSON_Delete(root);
    free(message);
}

/* Private: Combine the given name and value into a JSON object (conforming to
 * the OpenXC standard) and send it out to the listener.
 *
 * name - The value for the name field of the OpenXC message.
 * value - The numerical, string or booelan for the value field of the OpenXC
 *     message.
 * event - (Optional) The event for the event field of the OpenXC message.
 * listener - The listener device to send on.
 */
void sendJSONMessage(const char* name, cJSON* value, cJSON* event,
        Listener* listener) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, name);
    cJSON_AddItemToObject(root, VALUE_FIELD_NAME, value);
    if(event != NULL) {
        cJSON_AddItemToObject(root, EVENT_FIELD_NAME, event);
    }
    sendJSON(root, listener);
}

/* Private: Determine if the received signal should be sent out and update
 * signal metadata.
 *
 * signal - The signal to look for in the CAN message data.
 * data - The data of the CAN message.
 * send - Will be flipped to false if the signal should not be sent (e.g. the
 *      signal is on a limited send frequency and the timer is not up yet).
 *
 * Returns the float value of the signal decoded from the data.
 */
float preTranslate(CanSignal* signal, uint64_t data, bool* send) {
    float value = decodeCanSignal(signal, data);

    if(!signal->received || signal->sendClock == signal->sendFrequency - 1) {
        if(send && (!signal->received || signal->sendSame ||
                    value != signal->lastValue)) {
            signal->received = true;
        } else {
            *send = false;
        }
        signal->sendClock = 0;
    } else {
        *send = false;
        ++signal->sendClock;
    }
    return value;
}

/* Private: Update signal metadata after translating and sending.
 *
 * We keep track of the last value of each CAN signal (in its raw float form),
 * but we can't update the value until after all translation has happened,
 * in case a custom handler needs to use the value.
 */
void postTranslate(CanSignal* signal, float value) {
    signal->lastValue = value;
}

float decodeCanSignal(CanSignal* signal, uint64_t data) {
    uint64_t rawValue = getBitField(data, signal->bitPosition,
            signal->bitSize);
    return rawValue * signal->factor + signal->offset;
}

float passthroughHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value;
}

bool booleanHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value == 0.0 ? false : true;
}

float ignoreHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    *send = false;
    return value;
}

const char* stateHandler(CanSignal* signal, CanSignal* signals,
        int signalCount, float value, bool* send) {
    CanSignalState* signalState = lookupSignalState(value, signal, signals,
            signalCount);
    if(signalState != NULL) {
        return signalState->name;
    }
    debug("No signal state found for value %d", value);
    *send = false;
    return NULL;
}

void sendNumericalMessage(const char* name, float value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateNumber(value), NULL, listener);
}

void sendBooleanMessage(const char* name, bool value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateBool(value), NULL, listener);
}

void sendStringMessage(const char* name, const char* value,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), NULL, listener);
}

void sendEventedBooleanMessage(const char* name, const char* value, bool event,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateBool(event),
            listener);
}

void sendEventedStringMessage(const char* name, const char* value,
        const char* event, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateString(event),
            listener);
}

void passthroughCanMessage(Listener* listener, int id, uint64_t data) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, ID_FIELD_NAME, id);

    char encodedData[67];
    union {
        uint64_t whole;
        uint8_t bytes[8];
    } combined;
    combined.whole = data;

    sprintf(encodedData, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
            combined.bytes[0],
            combined.bytes[1],
            combined.bytes[2],
            combined.bytes[3],
            combined.bytes[4],
            combined.bytes[5],
            combined.bytes[6],
            combined.bytes[7]);
    cJSON_AddStringToObject(root, DATA_FIELD_NAME, encodedData);

    sendJSON(root, listener);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        float (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    if(send) {
        float processedValue = handler(signal, signals, signalCount, value,
                &send);
        if(send) {
            sendNumericalMessage(signal->genericName, processedValue, listener);
        }
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        const char* (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    if(send) {
        const char* stringValue = handler(signal, signals, signalCount, value,
                &send);
        if(stringValue == NULL) {
            debug("No valid string returned from handler for %s",
                    signal->genericName);
        } else if(send) {
            sendStringMessage(signal->genericName, stringValue, listener);
        }
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        bool (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    if(send) {
        bool booleanValue = handler(signal, signals, signalCount, value, &send);
        if(send) {
            sendBooleanMessage(signal->genericName, booleanValue, listener);
        }
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data, CanSignal* signals, int signalCount) {
    translateCanSignal(listener, signal, data, passthroughHandler, signals,
            signalCount);
}
<commit_msg>In the float translateCanSignal(), I removed the if(send) check around the handler call.  But I left the check around the sendNumericalMessage() call.  The change means that now the handler gets called for every message, but a JSON message is only sent as allowed by the send flag.<commit_after>#include "canread.h"
#include <stdlib.h>
#include "log.h"

/* Private: Serialize the root JSON object to a string (ending with a newline)
 * and send it to the listener.
 *
 * root - The JSON object to send.
 * listener - The listener device to send on.
 */
void sendJSON(cJSON* root, Listener* listener) {
    char* message = cJSON_PrintUnformatted(root);
    sendMessage(listener, (uint8_t*) message, strlen(message));
    cJSON_Delete(root);
    free(message);
}

/* Private: Combine the given name and value into a JSON object (conforming to
 * the OpenXC standard) and send it out to the listener.
 *
 * name - The value for the name field of the OpenXC message.
 * value - The numerical, string or booelan for the value field of the OpenXC
 *     message.
 * event - (Optional) The event for the event field of the OpenXC message.
 * listener - The listener device to send on.
 */
void sendJSONMessage(const char* name, cJSON* value, cJSON* event,
        Listener* listener) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, name);
    cJSON_AddItemToObject(root, VALUE_FIELD_NAME, value);
    if(event != NULL) {
        cJSON_AddItemToObject(root, EVENT_FIELD_NAME, event);
    }
    sendJSON(root, listener);
}

/* Private: Determine if the received signal should be sent out and update
 * signal metadata.
 *
 * signal - The signal to look for in the CAN message data.
 * data - The data of the CAN message.
 * send - Will be flipped to false if the signal should not be sent (e.g. the
 *      signal is on a limited send frequency and the timer is not up yet).
 *
 * Returns the float value of the signal decoded from the data.
 */
float preTranslate(CanSignal* signal, uint64_t data, bool* send) {
    float value = decodeCanSignal(signal, data);

    if(!signal->received || signal->sendClock == signal->sendFrequency - 1) {
        if(send && (!signal->received || signal->sendSame ||
                    value != signal->lastValue)) {
            signal->received = true;
        } else {
            *send = false;
        }
        signal->sendClock = 0;
    } else {
        *send = false;
        ++signal->sendClock;
    }
    return value;
}

/* Private: Update signal metadata after translating and sending.
 *
 * We keep track of the last value of each CAN signal (in its raw float form),
 * but we can't update the value until after all translation has happened,
 * in case a custom handler needs to use the value.
 */
void postTranslate(CanSignal* signal, float value) {
    signal->lastValue = value;
}

float decodeCanSignal(CanSignal* signal, uint64_t data) {
    uint64_t rawValue = getBitField(data, signal->bitPosition,
            signal->bitSize);
    return rawValue * signal->factor + signal->offset;
}

float passthroughHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value;
}

bool booleanHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value == 0.0 ? false : true;
}

float ignoreHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    *send = false;
    return value;
}

const char* stateHandler(CanSignal* signal, CanSignal* signals,
        int signalCount, float value, bool* send) {
    CanSignalState* signalState = lookupSignalState(value, signal, signals,
            signalCount);
    if(signalState != NULL) {
        return signalState->name;
    }
    debug("No signal state found for value %d", value);
    *send = false;
    return NULL;
}

void sendNumericalMessage(const char* name, float value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateNumber(value), NULL, listener);
}

void sendBooleanMessage(const char* name, bool value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateBool(value), NULL, listener);
}

void sendStringMessage(const char* name, const char* value,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), NULL, listener);
}

void sendEventedBooleanMessage(const char* name, const char* value, bool event,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateBool(event),
            listener);
}

void sendEventedStringMessage(const char* name, const char* value,
        const char* event, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateString(event),
            listener);
}

void passthroughCanMessage(Listener* listener, int id, uint64_t data) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, ID_FIELD_NAME, id);

    char encodedData[67];
    union {
        uint64_t whole;
        uint8_t bytes[8];
    } combined;
    combined.whole = data;

    sprintf(encodedData, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
            combined.bytes[0],
            combined.bytes[1],
            combined.bytes[2],
            combined.bytes[3],
            combined.bytes[4],
            combined.bytes[5],
            combined.bytes[6],
            combined.bytes[7]);
    cJSON_AddStringToObject(root, DATA_FIELD_NAME, encodedData);

    sendJSON(root, listener);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        float (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    float processedValue = handler(signal, signals, signalCount, value,
                &send);
    if(send) {
        sendNumericalMessage(signal->genericName, processedValue, listener);
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        const char* (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    if(send) {
        const char* stringValue = handler(signal, signals, signalCount, value,
                &send);
        if(stringValue == NULL) {
            debug("No valid string returned from handler for %s",
                    signal->genericName);
        } else if(send) {
            sendStringMessage(signal->genericName, stringValue, listener);
        }
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        bool (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    bool send = true;
    float value = preTranslate(signal, data, &send);
    if(send) {
        bool booleanValue = handler(signal, signals, signalCount, value, &send);
        if(send) {
            sendBooleanMessage(signal->genericName, booleanValue, listener);
        }
    }
    postTranslate(signal, value);
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data, CanSignal* signals, int signalCount) {
    translateCanSignal(listener, signal, data, passthroughHandler, signals,
            signalCount);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#include "addressbookpage.h"
#include "ui_addressbookpage.h"

#include "addresstablemodel.h"
#include "bitcoingui.h"
#include "csvmodelwriter.h"
#include "editaddressdialog.h"
#include "guiutil.h"

#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>

AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    mode(mode),
    tab(tab)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
    ui->newAddress->setIcon(QIcon());
    ui->copyAddress->setIcon(QIcon());
    ui->deleteAddress->setIcon(QIcon());
    ui->exportButton->setIcon(QIcon());
#endif

    switch(mode)
    {
    case ForSelection:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
        case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
        }
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        ui->closeButton->setText(tr("C&hoose"));
        ui->exportButton->hide();
        break;
    case ForEditing:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Sending addresses")); break;
        case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break;
        }
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setText(tr("These are your Dogecoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
        ui->deleteAddress->setVisible(true);
        break;
    case ReceivingTab:
        ui->labelExplanation->setText(tr("These are your Dogecoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
        ui->deleteAddress->setVisible(false);
        break;
    }

    // Context menu actions
    QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    deleteAction = new QAction(ui->deleteAddress->text(), this);

    // Build context menu
    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept()));
}

AddressBookPage::~AddressBookPage()
{
    delete ui;
}

void AddressBookPage::setModel(AddressTableModel *model)
{
    this->model = model;
    if(!model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
#if QT_VERSION < 0x050000
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#endif

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
        this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::on_copyAddress_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!model)
        return;

    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::EditSendingAddress :
        EditAddressDialog::EditReceivingAddress, this);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_newAddress_clicked()
{
    if(!model)
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::NewSendingAddress :
        EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteAddress_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteAddress->setEnabled(true);
            ui->deleteAddress->setVisible(true);
            deleteAction->setEnabled(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteAddress->setEnabled(false);
            ui->deleteAddress->setVisible(false);
            deleteAction->setEnabled(false);
            break;
        }
        ui->copyAddress->setEnabled(true);
    }
    else
    {
        ui->deleteAddress->setEnabled(false);
        ui->copyAddress->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::on_exportButton_clicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Export Address List"), QString(),
        tr("Comma separated file (*.csv)"), NULL);

    if (filename.isNull())
        return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write()) {
        QMessageBox::critical(this, tr("Exporting Failed"),
            tr("There was an error trying to save the address list to %1.").arg(filename));
    }
}

void AddressBookPage::contextualMenu(const QPoint &point)
{
    QModelIndex index = ui->tableView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}
<commit_msg>Update addressbookpage.cpp<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#include "addressbookpage.h"
#include "ui_addressbookpage.h"

#include "addresstablemodel.h"
#include "bitcoingui.h"
#include "csvmodelwriter.h"
#include "editaddressdialog.h"
#include "guiutil.h"

#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>

AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    mode(mode),
    tab(tab)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
    ui->newAddress->setIcon(QIcon());
    ui->copyAddress->setIcon(QIcon());
    ui->deleteAddress->setIcon(QIcon());
    ui->exportButton->setIcon(QIcon());
#endif

    switch(mode)
    {
    case ForSelection:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
        case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
        }
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        ui->closeButton->setText(tr("C&hoose"));
        ui->exportButton->hide();
        break;
    case ForEditing:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Very sending addresses")); break;
        case ReceivingTab: setWindowTitle(tr("Much receiving addresses")); break;
        }
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setText(tr("These are your Dogecoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
        ui->deleteAddress->setVisible(true);
        break;
    case ReceivingTab:
        ui->labelExplanation->setText(tr("These are your Dogecoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
        ui->deleteAddress->setVisible(false);
        break;
    }

    // Context menu actions
    QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    deleteAction = new QAction(ui->deleteAddress->text(), this);

    // Build context menu
    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept()));
}

AddressBookPage::~AddressBookPage()
{
    delete ui;
}

void AddressBookPage::setModel(AddressTableModel *model)
{
    this->model = model;
    if(!model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
#if QT_VERSION < 0x050000
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#endif

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
        this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::on_copyAddress_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!model)
        return;

    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::EditSendingAddress :
        EditAddressDialog::EditReceivingAddress, this);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_newAddress_clicked()
{
    if(!model)
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::NewSendingAddress :
        EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteAddress_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteAddress->setEnabled(true);
            ui->deleteAddress->setVisible(true);
            deleteAction->setEnabled(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteAddress->setEnabled(false);
            ui->deleteAddress->setVisible(false);
            deleteAction->setEnabled(false);
            break;
        }
        ui->copyAddress->setEnabled(true);
    }
    else
    {
        ui->deleteAddress->setEnabled(false);
        ui->copyAddress->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::on_exportButton_clicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Export Address List"), QString(),
        tr("Comma separated file (*.csv)"), NULL);

    if (filename.isNull())
        return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write()) {
        QMessageBox::critical(this, tr("Exporting Failed"),
            tr("There was an error trying to save the address list to %1.").arg(filename));
    }
}

void AddressBookPage::contextualMenu(const QPoint &point)
{
    QModelIndex index = ui->tableView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2009 Soeren Sonnenburg
 * Copyright (C) 2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/lib/memory.h>
#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/Random.h>
#include <shogun/io/SGIO.h>
#include <shogun/base/Parallel.h>
#include <shogun/base/Version.h>
#include <shogun/base/SGRefObject.h>
#include <stdlib.h>
#include <string.h>

#ifdef TRACE_MEMORY_ALLOCS
#include <shogun/lib/Map.h>
shogun::CMap<void*, shogun::MemoryBlock>* sg_mallocs=NULL;
#endif

namespace shogun
{
	Parallel* sg_parallel=NULL;
	SGIO* sg_io=NULL;
	Version* sg_version=NULL;
	CMath* sg_math=NULL;
	CRandom* sg_rand=NULL;

	/// function called to print normal messages
	void (*sg_print_message)(FILE* target, const char* str) = NULL;

	/// function called to print warning messages
	void (*sg_print_warning)(FILE* target, const char* str) = NULL;

	/// function called to print error messages
	void (*sg_print_error)(FILE* target, const char* str) = NULL;

	/// function called to cancel things
	void (*sg_cancel_computations)(bool &delayed, bool &immediately)=NULL;

	void init_shogun(void (*print_message)(FILE* target, const char* str),
			void (*print_warning)(FILE* target, const char* str),
			void (*print_error)(FILE* target, const char* str),
			void (*cancel_computations)(bool &delayed, bool &immediately))
	{
		if (!sg_io)
			sg_io = new shogun::SGIO();
		if (!sg_parallel)
			sg_parallel=new shogun::Parallel();
		if (!sg_version)
			sg_version = new shogun::Version();
		if (!sg_math)
			sg_math = new shogun::CMath();
		if (!sg_rand)
			sg_rand = new shogun::CRandom();
#ifdef TRACE_MEMORY_ALLOCS
		if (!sg_mallocs)
			sg_mallocs = new shogun::CMap<void*, MemoryBlock>(631, 1024, false);

		SG_REF(sg_mallocs);
#endif
		SG_REF(sg_io);
		SG_REF(sg_parallel);
		SG_REF(sg_version);
		SG_REF(sg_math);
		SG_REF(sg_rand);

		sg_print_message=print_message;
		sg_print_warning=print_warning;
		sg_print_error=print_error;
		sg_cancel_computations=cancel_computations;

		init_from_env();
	}

	void sg_global_print_default(FILE* target, const char* str)
	{
		fprintf(target, "%s", str);
	}

	void init_shogun_with_defaults()
	{
		init_shogun(&sg_global_print_default, &sg_global_print_default,
				&sg_global_print_default);
	}

	void exit_shogun()
	{
#ifdef TRACE_MEMORY_ALLOCS
		list_memory_allocs();
		shogun::CMap<void*, shogun::MemoryBlock>* mallocs=sg_mallocs;
		sg_mallocs=NULL;
		SG_UNREF(mallocs);
#endif
		sg_print_message=NULL;
		sg_print_warning=NULL;
		sg_print_error=NULL;
		sg_cancel_computations=NULL;

		SG_UNREF(sg_rand);
		SG_UNREF(sg_math);
		SG_UNREF(sg_version);
		SG_UNREF(sg_parallel);
		SG_UNREF(sg_io);

	}

	void set_global_io(SGIO* io)
	{
		SG_REF(io);
		SG_UNREF(sg_io);
		sg_io=io;
	}

	SGIO* get_global_io()
	{
		SG_REF(sg_io);
		return sg_io;
	}

	void set_global_parallel(Parallel* parallel)
	{
		SG_REF(parallel);
		SG_UNREF(sg_parallel);
		sg_parallel=parallel;
	}

	Parallel* get_global_parallel()
	{
		SG_REF(sg_parallel);
		return sg_parallel;
	}

	void set_global_version(Version* version)
	{
		SG_REF(version);
		SG_UNREF(sg_version);
		sg_version=version;
	}

	Version* get_global_version()
	{
		SG_REF(sg_version);
		return sg_version;
	}

	void set_global_math(CMath* math)
	{
		SG_REF(math);
		SG_UNREF(sg_math);
		sg_math=math;
	}

	CMath* get_global_math()
	{
		SG_REF(sg_math);
		return sg_math;
	}

	void set_global_rand(CRandom* rand)
	{
		SG_REF(rand);
		SG_UNREF(sg_rand);
		sg_rand=rand;
	}

	CRandom* get_global_rand()
	{
		SG_REF(sg_rand);
		return sg_rand;
	}

	void init_from_env()
	{
		char* env_log_val = NULL;
		SGIO* io = get_global_io();
		env_log_val = getenv("SHOGUN_LOG_LEVEL");
		if (env_log_val)
		{
			if(strncmp(env_log_val, "DEBUG", 5) == 0)
				io->set_loglevel(MSG_DEBUG);
			else if(strncmp(env_log_val, "WARN", 4) == 0)
				io->set_loglevel(MSG_WARN);
			else if(strncmp(env_log_val, "ERROR", 5) == 0)
				io->set_loglevel(MSG_ERROR);
		}
		SG_UNREF(io);
	}
}
<commit_msg>Cleaning up protobuf library in exit_shogun().<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2009 Soeren Sonnenburg
 * Copyright (C) 2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/lib/memory.h>
#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/Random.h>
#include <shogun/io/SGIO.h>
#include <shogun/base/Parallel.h>
#include <shogun/base/Version.h>
#include <shogun/base/SGRefObject.h>
#include <stdlib.h>
#include <string.h>

#ifdef TRACE_MEMORY_ALLOCS
#include <shogun/lib/Map.h>
shogun::CMap<void*, shogun::MemoryBlock>* sg_mallocs=NULL;
#endif

#ifdef HAVE_PROTOBUF
#include <shogun/io/protobuf/Headers.pb.h>
#endif

namespace shogun
{
	Parallel* sg_parallel=NULL;
	SGIO* sg_io=NULL;
	Version* sg_version=NULL;
	CMath* sg_math=NULL;
	CRandom* sg_rand=NULL;

	/// function called to print normal messages
	void (*sg_print_message)(FILE* target, const char* str) = NULL;

	/// function called to print warning messages
	void (*sg_print_warning)(FILE* target, const char* str) = NULL;

	/// function called to print error messages
	void (*sg_print_error)(FILE* target, const char* str) = NULL;

	/// function called to cancel things
	void (*sg_cancel_computations)(bool &delayed, bool &immediately)=NULL;

	void init_shogun(void (*print_message)(FILE* target, const char* str),
			void (*print_warning)(FILE* target, const char* str),
			void (*print_error)(FILE* target, const char* str),
			void (*cancel_computations)(bool &delayed, bool &immediately))
	{
		if (!sg_io)
			sg_io = new shogun::SGIO();
		if (!sg_parallel)
			sg_parallel=new shogun::Parallel();
		if (!sg_version)
			sg_version = new shogun::Version();
		if (!sg_math)
			sg_math = new shogun::CMath();
		if (!sg_rand)
			sg_rand = new shogun::CRandom();
#ifdef TRACE_MEMORY_ALLOCS
		if (!sg_mallocs)
			sg_mallocs = new shogun::CMap<void*, MemoryBlock>(631, 1024, false);

		SG_REF(sg_mallocs);
#endif
		SG_REF(sg_io);
		SG_REF(sg_parallel);
		SG_REF(sg_version);
		SG_REF(sg_math);
		SG_REF(sg_rand);

		sg_print_message=print_message;
		sg_print_warning=print_warning;
		sg_print_error=print_error;
		sg_cancel_computations=cancel_computations;

		init_from_env();
	}

	void sg_global_print_default(FILE* target, const char* str)
	{
		fprintf(target, "%s", str);
	}

	void init_shogun_with_defaults()
	{
		init_shogun(&sg_global_print_default, &sg_global_print_default,
				&sg_global_print_default);
	}

	void exit_shogun()
	{
#ifdef TRACE_MEMORY_ALLOCS
		list_memory_allocs();
		shogun::CMap<void*, shogun::MemoryBlock>* mallocs=sg_mallocs;
		sg_mallocs=NULL;
		SG_UNREF(mallocs);
#endif
		sg_print_message=NULL;
		sg_print_warning=NULL;
		sg_print_error=NULL;
		sg_cancel_computations=NULL;

		SG_UNREF(sg_rand);
		SG_UNREF(sg_math);
		SG_UNREF(sg_version);
		SG_UNREF(sg_parallel);
		SG_UNREF(sg_io);

#ifdef HAVE_PROTOBUF
		::google::protobuf::ShutdownProtobufLibrary();
#endif
	}

	void set_global_io(SGIO* io)
	{
		SG_REF(io);
		SG_UNREF(sg_io);
		sg_io=io;
	}

	SGIO* get_global_io()
	{
		SG_REF(sg_io);
		return sg_io;
	}

	void set_global_parallel(Parallel* parallel)
	{
		SG_REF(parallel);
		SG_UNREF(sg_parallel);
		sg_parallel=parallel;
	}

	Parallel* get_global_parallel()
	{
		SG_REF(sg_parallel);
		return sg_parallel;
	}

	void set_global_version(Version* version)
	{
		SG_REF(version);
		SG_UNREF(sg_version);
		sg_version=version;
	}

	Version* get_global_version()
	{
		SG_REF(sg_version);
		return sg_version;
	}

	void set_global_math(CMath* math)
	{
		SG_REF(math);
		SG_UNREF(sg_math);
		sg_math=math;
	}

	CMath* get_global_math()
	{
		SG_REF(sg_math);
		return sg_math;
	}

	void set_global_rand(CRandom* rand)
	{
		SG_REF(rand);
		SG_UNREF(sg_rand);
		sg_rand=rand;
	}

	CRandom* get_global_rand()
	{
		SG_REF(sg_rand);
		return sg_rand;
	}

	void init_from_env()
	{
		char* env_log_val = NULL;
		SGIO* io = get_global_io();
		env_log_val = getenv("SHOGUN_LOG_LEVEL");
		if (env_log_val)
		{
			if(strncmp(env_log_val, "DEBUG", 5) == 0)
				io->set_loglevel(MSG_DEBUG);
			else if(strncmp(env_log_val, "WARN", 4) == 0)
				io->set_loglevel(MSG_WARN);
			else if(strncmp(env_log_val, "ERROR", 5) == 0)
				io->set_loglevel(MSG_ERROR);
		}
		SG_UNREF(io);
	}
}
<|endoftext|>


<commit_before>#include "world.h"

#include "../core/console.h"
#include "../core/content.h"
#include "../util/mathutils.h"
#include "../util/log.h"

#include "cell.h"
#include "food.h"
#include "water.h"

#include <sstream>
#include <iostream>

NeuralNetwork* World::m_neuralNetwork = 0;
uint32 World::m_weightCount = 0;

// 8192.0f
World::World() :
    m_radius(2048.0f),
    m_spatialHash(m_radius),
    m_debug(false)
{
    std::cout << "world ctor" << std::endl;

    // TODO (Tyler): Fine tune the hidden nodes.
    m_neuralNetwork = new NeuralNetwork(11, 8, 4);
    m_weightCount = m_neuralNetwork->getWeightCount();
}

World::~World()
{
    std::cout << "world dtor" << std::endl;

    if (m_neuralNetwork)
        delete m_neuralNetwork;

    m_neuralNetwork = 0;
}

bool World::initialize()
{
    m_border.setRadius(m_radius);
    m_border.setOrigin(m_radius, m_radius);
    m_border.setFillColor(sf::Color(32, 32, 32, 255));
    m_border.setOutlineColor(sf::Color(128, 128, 128, 255));
    m_border.setOutlineThickness(10.0f);
    m_border.setPointCount(100);

    m_vertexQuadArray.setPrimitiveType(sf::Quads);
    m_vertexLineArray.setPrimitiveType(sf::Lines);

    m_debugText = new sf::Text();
    m_debugText->setFont(*Content::font);
    m_debugText->setPosition(0.0f, 100.0f);
    m_debugText->setCharacterSize(16);

    for (int32 i = 0; i < 500; i++) {
        Cell* newCell = new Cell(1, Genome(), randomWorldPoint(), *this);
        newCell->setMass(100.0f);
        m_entities.push_back(newCell);
    }

    for (int32 i = 0; i < 200; i++)
       m_entities.push_back(new Food(randomWorldPoint(), *this));

    m_spatialHash.buildArray(m_vertexQuadArray, sf::Quads);
    m_spatialHash.buildArray(m_vertexLineArray, sf::Lines);

    updateEntityText();

    return true;
}

void World::destroy()
{
    if (m_debugText)
        delete m_debugText;

    for (auto& entity : m_entities) {
        delete entity;
    }

    m_entities.clear();
}

void World::update(const float dt)
{
    bool hasChanged = false;
    bool entityDied = false;

    for (int32 i = m_entities.size() - 1; i >= 0; i--) {
        Entity* entity = m_entities[i];
        if (entity->isAlive()) {

            entity->update(dt);

            if (entity->updateHash()) {
                m_spatialHash.update(entity);
                hasChanged = true;
            }
        }
        else {

            m_entities.erase(m_entities.begin() + i);
            onDeath(entity);

            // Make sure we remove the entity from the spatialhash and all of the nodes that it exists in.
            // This can cause problems because a node may contain a null reference to an entity which causesa c crash.
            m_spatialHash.remove(entity);

            delete entity;
            entityDied = true;
        }
    }

    if (hasChanged && m_debug) {
        m_vertexQuadArray.clear();
        m_vertexLineArray.clear();
        m_spatialHash.buildArray(m_vertexQuadArray, sf::Quads);
        m_spatialHash.buildArray(m_vertexLineArray, sf::Lines);
    }

    if (entityDied) {
        updateEntityText();
    }
}

void World::updateEntityText()
{
    std::stringstream sb;
    sb << "entity count: " << m_entities.size() << ", cell count: " << Cell::m_cellCount;
    m_debugText->setString(sb.str());
}

void World::onDeath(Entity* entity)
{
    if (entity->getType() == type::Cell) {

        Cell* cell = (Cell*)entity;
        if (cell) {

            std::stringstream sb;
            sb << "entity died at generation: " << cell->getGeneration();

            Console::write(sb.str());
        }

    }
    else if (entity->getType() == type::Resource) {

        Resource* resource = (Resource*)entity;
        if (resource->getResourceType() == type::Food) {
            m_entities.push_back(new Food(randomWorldPoint(), *this));
        }
        else if (resource->getResourceType() == type::Water) {
            m_entities.push_back(new Water(randomWorldPoint(), *this));
        }
    }
}

void World::render(sf::RenderTarget& target, Camera& camera, const sf::View& textView)
{
    // Setup the camera view for the world
    camera.render(target);

    target.draw(m_border, Content::shader);

    if (m_debug) {
        target.draw(m_vertexQuadArray, Content::shader);
        target.draw(m_vertexLineArray, Content::shader);
    }

    for (auto& entity : m_entities) {

        if (entity->isAlive()) {
            entity->render(target);
        }
    }

    target.setView(textView);
    target.draw(*m_debugText);
}

vec2f World::randomWorldPoint()
{
    // Generate a random angle between 0 and 2(Pi).
    const real32 theta = randomFloat(0.0f) * nx::Pi * 2.0f;
    return vec2f(std::cos(theta) * randomFloat(0.0f, m_radius),
                 std::sin(theta) * randomFloat(0.0f, m_radius));
}

void World::add(Entity* entity)
{
    // Make sure there is never a null entity added.
    if (entity == 0) {
        return;
    }

    m_entities.push_back(entity);
}

bool World::isPointInWorld(vec2f point)
{
    const vec2f delta = point * point;

    return (delta.x + delta.y <= m_radius * m_radius);
}

bool World::isEntityInWorld(Entity* entity)
{
    // Well a null entity can't exist in the world so ya..
    if (entity == 0) {
        return false;
    }

    return isPointInWorld(entity->getLocation());
}
<commit_msg>Minor formatting in the world class.<commit_after>#include "world.h"

#include "../core/console.h"
#include "../core/content.h"
#include "../util/mathutils.h"
#include "../util/log.h"

#include "cell.h"
#include "food.h"
#include "water.h"

#include <sstream>

NeuralNetwork* World::m_neuralNetwork = 0;
uint32 World::m_weightCount = 0;

// 8192.0f
World::World() :
    m_radius(2048.0f),
    m_spatialHash(m_radius),
    m_debug(false)
{
    // TODO (Tyler): Fine tune the hidden nodes.
    m_neuralNetwork = new NeuralNetwork(11, 8, 4);
    m_weightCount = m_neuralNetwork->getWeightCount();
}

World::~World()
{
    if (m_neuralNetwork)
        delete m_neuralNetwork;

    m_neuralNetwork = 0;
}

bool World::initialize()
{
    m_border.setRadius(m_radius);
    m_border.setOrigin(m_radius, m_radius);
    m_border.setFillColor(sf::Color(32, 32, 32, 255));
    m_border.setOutlineColor(sf::Color(128, 128, 128, 255));
    m_border.setOutlineThickness(10.0f);
    m_border.setPointCount(100);

    m_vertexQuadArray.setPrimitiveType(sf::Quads);
    m_vertexLineArray.setPrimitiveType(sf::Lines);

    m_debugText = new sf::Text();
    m_debugText->setFont(*Content::font);
    m_debugText->setPosition(0.0f, 100.0f);
    m_debugText->setCharacterSize(16);

    for (int32 i = 0; i < 500; i++) {
        Cell* newCell = new Cell(1, Genome(), randomWorldPoint(), *this);
        newCell->setMass(100.0f);
        m_entities.push_back(newCell);
    }

    for (int32 i = 0; i < 200; i++)
       m_entities.push_back(new Food(randomWorldPoint(), *this));

    m_spatialHash.buildArray(m_vertexQuadArray, sf::Quads);
    m_spatialHash.buildArray(m_vertexLineArray, sf::Lines);

    updateEntityText();

    return true;
}

void World::destroy()
{
    if (m_debugText)
        delete m_debugText;

    for (auto& entity : m_entities) {
        delete entity;
    }

    m_entities.clear();
}

void World::update(const float dt)
{
    bool hasChanged = false;
    bool entityDied = false;

    for (int32 i = m_entities.size() - 1; i >= 0; i--) {
        Entity* entity = m_entities[i];
        if (entity->isAlive()) {

            entity->update(dt);

            if (entity->updateHash()) {
                m_spatialHash.update(entity);
                hasChanged = true;
            }
        }
        else {

            m_entities.erase(m_entities.begin() + i);
            onDeath(entity);

            // Make sure we remove the entity from the spatialhash and all of the nodes that it exists in.
            // This can cause problems because a node may contain a null reference to an entity which causesa c crash.
            m_spatialHash.remove(entity);

            delete entity;
            entityDied = true;
        }
    }

    if (hasChanged && m_debug) {
        m_vertexQuadArray.clear();
        m_vertexLineArray.clear();
        m_spatialHash.buildArray(m_vertexQuadArray, sf::Quads);
        m_spatialHash.buildArray(m_vertexLineArray, sf::Lines);
    }

    if (entityDied) {
        updateEntityText();
    }
}

void World::updateEntityText()
{
    std::stringstream sb;
    sb << "entity count: " << m_entities.size() << ", cell count: " << Cell::m_cellCount;
    m_debugText->setString(sb.str());
}

void World::onDeath(Entity* entity)
{
    if (entity->getType() == type::Cell) {

        Cell* cell = (Cell*)entity;
        if (cell) {

            std::stringstream sb;
            sb << "entity died at generation: " << cell->getGeneration();

            Console::write(sb.str());
        }

    }
    else if (entity->getType() == type::Resource) {

        Resource* resource = (Resource*)entity;
        if (resource->getResourceType() == type::Food) {
            m_entities.push_back(new Food(randomWorldPoint(), *this));
        }
        else if (resource->getResourceType() == type::Water) {
            m_entities.push_back(new Water(randomWorldPoint(), *this));
        }
    }
}

void World::render(sf::RenderTarget& target, Camera& camera, const sf::View& textView)
{
    // Setup the camera view for the world
    camera.render(target);

    target.draw(m_border, Content::shader);

    if (m_debug) {
        target.draw(m_vertexQuadArray, Content::shader);
        target.draw(m_vertexLineArray, Content::shader);
    }

    for (auto& entity : m_entities) {

        if (entity->isAlive()) {
            entity->render(target);
        }
    }

    target.setView(textView);
    target.draw(*m_debugText);
}

vec2f World::randomWorldPoint()
{
    // Generate a random angle between 0 and 2(Pi).
    const real32 theta = randomFloat(0.0f) * nx::Pi * 2.0f;
    return vec2f(std::cos(theta) * randomFloat(0.0f, m_radius),
                 std::sin(theta) * randomFloat(0.0f, m_radius));
}

void World::add(Entity* entity)
{
    // Make sure there is never a null entity added.
    if (entity == 0) {
        return;
    }

    m_entities.push_back(entity);
}

bool World::isPointInWorld(vec2f point)
{
    const vec2f delta = point * point;

    return (delta.x + delta.y <= m_radius * m_radius);
}

bool World::isEntityInWorld(Entity* entity)
{
    // Well a null entity can't exist in the world so ya..
    if (entity == 0) {
        return false;
    }

    return isPointInWorld(entity->getLocation());
}
<|endoftext|>