0
votes

So I am doing this in a header file gui_base.hpp "gui_flags" is simply a definition of bitflags, nsp_input is needed to access a variable in "handle mouse" and in gui_text.hpp i declare the textblock class. Every "gui_" file is in the GUI:: namespace.

#ifndef _GUI_BASE_HPP_
#define _GUI_BASE_HPP_

#include "gui_flags.hpp"
#include "nsp_input.hpp"
#include "gui_text.hpp"


class GUI::base
{
protected:
  struct s_lastclick
  {
    float ltime,rtime;
    glm::vec2 pos;
    bool rc, lc, first;
  };

  std::string m_name;

  float m_width;
  float m_height;

  glm::vec2 m_center;
  glm::mat2x2 m_tlbr;

  GUI_FLAGS m_flags;

  s_lastclick m_lastclick;
  textblock m_textblock;



  std::map<std::string, std::shared_ptr<base>> m_slaves;

  glm::vec4 color;

public:
  base(std::string gn, float &gw, float &gh, glm::vec2 &gc);

  bool check_borders();

  void move(glm::vec2 &gpos);
  void move(float &x, float &y);

  void toggle_flags(GUI_FLAGS f);
  void open();
  void close();

  void set_color(glm::vec3 &color);
  void set_transparency(float &t);

  void enslave(std::string name, std::shared_ptr<base> &gslave);
  void free_slave(std::string name);
  void check_slaves();

  void add_text(std::string text, glm::vec2 position, glm::vec3 color,
                GLfloat scale=1.0f, GLfloat padx=8.0f, GLfloat pady=8.0f);

  virtual void handle_mouse();
  virtual void handle_keys();

};

#endif // _GUI_BASE_HPP_

If more details are needed, I can copy them here, I just didn't want to spam too much code.

The compiler simply gives two errors:

obj\Debug\Sources\gui_base.o:c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\mingw32\bits\gthr-default.h|402|first defined here|

||error: ld returned 1 exit status|

||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|

All variables and funtions are defined in gui_base.cpp (including the virtual ones). I am more or less transferring it "into" the namespace, as I had it working as a "normal" class in the global namespace just fine, so I assume it has soemthing to do with it. But given my lack of experience, I am a little overwhelmed by the small amount of (for me) understandable information given by the compiler error.

Most entries I could find were multiple definition errors regarding definitions in the header files, which - in my understanding - I do not have in my header.

Here is the gui_base.cpp:

#include "../Headers/gui_base.hpp"

namespace input_handler
{
  std::unique_ptr<s_mouse> up_mouse;
  std::map<uint32_t, bool> KEYS;
}

GUI::base::base(std::string gn, float &gw, float &gh, glm::vec2 &gc) : m_name(gn),
                                                                          m_width(gw),
                                                                          m_height(gh),
                                                                          m_center(gc)
{
  resource_manager::calc_tlbr(m_tlbr, m_center, m_width, m_height);
}

void GUI::base::handle_keys()
{

}
void GUI::base::handle_mouse()
{

}
bool GUI::base::check_borders()
{
  if(input_handler::up_mouse->position.x > m_tlbr[0].x &&
     input_handler::up_mouse->position.y < m_tlbr[0].y &&
     input_handler::up_mouse->position.x < m_tlbr[1].x &&
     input_handler::up_mouse->position.y > m_tlbr[1].y)
      return true;
  else
    return false;
}

void GUI::base::move(glm::vec2 &gpos)
{
  m_center = gpos;
  resource_manager::calc_tlbr(m_tlbr, m_center, m_width, m_height);
}

void GUI::base::move(float &x, float &y)
{
  m_center = glm::vec2(x,y);
  resource_manager::calc_tlbr(m_tlbr, m_center, m_width, m_height);
}

void GUI::base::enslave(std::string name, std::shared_ptr<base> &gslave)
{
  m_slaves[name] = gslave;
}

void GUI::base::check_slaves()
{
  for(auto iter : m_slaves)
  {
    if(iter.second->check_borders())
    {
      if(iter.second->m_flags & GUI_OPEN)
        iter.second->check_slaves();
    }
    else
      continue;
  }
}

void GUI::base::open()
{
    toggle_flags(GUI_OPEN | GUI_DRAW | GUI_CLOSED);
    if(!m_slaves.empty())
    {
        for(auto iter : m_slaves)
        {
            iter.second->open();
        }
    }

}

void GUI::base::toggle_flags(GUI_FLAGS f)
{
  m_flags ^= f;
}

void GUI::base::close()
{
    toggle_flags(GUI_OPEN | GUI_DRAW | GUI_CLOSED);
    if(!m_slaves.empty())
    {
        for(auto iter : m_slaves)
        {
            iter.second->close();
        }
    }
}
void GUI::base::add_text(std::string text, glm::vec2 position, glm::vec3 color,
                GLfloat scale, GLfloat padx, GLfloat pady)
{
  m_textblock = GUI::textblock(position, color, scale, padx, pady, text);
}

EDIT: My class is declared in the nsp_gui.hpp file, which is included in the gui_text.hpp file (which is included in the regarding gui_base file)

there I declare my class as follows:

#ifndef _NSP_GUI_HPP_
#define _NSP_GUI_HPP_

namespace GUI
{
  //the renderer class
  class renderer;
  class base;
  class window;
  //init function -> text will be in the GUI
  extern void init_gui();
}

#endif // _NSP_GUI_HPP_

Blame on me - I found this in the build log (wasn't aware that there one.. sorry):

obj\Debug\Sources\gui_text.o:gui_text.cpp:(.bss+0x0): multiple definition of GUI::textblock_storage[abi:cxx11] obj\Debug\Sources\gui_base.o:gui_base.cpp:(.bss+0x0): first defined here obj\Debug\Sources\gui_window.o:gui_window.cpp:(.bss+0x0): multiple definition of GUI::textblock_storage[abi:cxx11]

textblock storage i declared in gui_text.hpp: (gui_window "simply" inherits from gui_base, so this may be why it is occuring in there)

#ifndef _GUI_TEXT_HPP_
#define _GUI_TEXT_HPP_

#include "nsp_rmng.hpp"
#include "nsp_gui.hpp"
#include <ft2build.h>
#include FT_FREETYPE_H

namespace GUI
{
  extern void init_alphabet();
  extern void write();
  class textblock
  {
  public:
    glm::vec2 position;
    glm::vec4 instancing;
    glm::vec3 color;
    GLfloat scale, padx, pady;
    std::string text;
    void calc_offsets();
    textblock(){};
    textblock(glm::vec2 &p, glm::vec3 &c,
                GLfloat &s, GLfloat &px, GLfloat &py,
                std::string &t);

  };
  std::map<std::string, textblock> textblock_storage;
}

#endif // _GUI_TEXT_HPP_

The strange thing is that I do not define it anywhere. I do not use it yet either in the base nor text.cpp, even though I want to use it within the gui_text.cpp. Shouldn't it be just an unknown reference then?

1

1 Answers

1
votes

obj\Debug\Sources\gui_base.o:c:\mingw\lib\gcc\mingw32\6.3.0\include\c++\mingw32\bits\gthr-default.h|402|first defined here|

It is not the error message.

Class class base in the namespace GUI should be declared like follow

namespace GUI {
class base {
  ...
};
} // namespace GUI

And definitions should be in the namespace too.

namespace GUI {
base::base(std::string gn, float &gw, float &gh, glm::vec2 &gc) {
  ...
}
} // namespace GUI

UPDATE after OP edited his answer.

The strange thing is that I do not define it anywhere.

You defined the variable textblock_storage in the header, the header is included twice at least, thus the variable takes places in obj-files several times. Declare it in the header like bellow

extern std::map<std::string, textblock> textblock_storage;

And define it once in only one .cpp file

std::map<std::string, textblock> textblock_storage;