Euphoria
load.cc
Go to the documentation of this file.
1 #include "gui/load.h"
2 
3 #include "log/log.h"
4 
5 #include "files/gui.h"
6 
7 #include "render/texturecache.h"
9 #include "render/fontcache.h"
10 
11 #include "gui/layoutcontainer.h"
12 #include "gui/layout.h"
13 #include "gui/button.h"
14 #include "gui/panelwidget.h"
15 #include "gui/skin.h"
16 #include "gui/root.h"
17 
18 #include <iostream>
19 #include <map>
20 
21 
22 
23 namespace eu::gui
24 {
25  std::shared_ptr<Layout>
27  {
28  if(c.table)
29  {
30  return create_table_layout
31  (
32  c.table->expanded_rows,
33  c.table->expanded_cols,
34  c.table->padding
35  );
36  }
37  else if(c.single_row)
38  {
39  return create_single_row_layout(c.single_row->padding);
40  }
41  else
42  {
43  ASSERT(false && "Missing a layout");
44  return create_single_row_layout(0);
45  }
46  }
47 
48 
49  struct CommandButton : public Button
50  {
52  : Button(state)
53  {
54  }
55 
56  void
57  on_clicked() override
58  {
59  // todo(Gustav): set up command to actually do something
60  LOG_INFO("Executing cmd: {0}", cmd);
61  }
62 
63  std::string cmd;
64  };
65 
66 
67  void
69  (
70  io::FileSystem* fs,
71  State* state,
72  LayoutContainer* root,
74  render::TextureCache* cache,
75  const std::map<std::string, Skin*>& skins
76  );
77 
78 
79  void
81  {
82  data->column = src.column;
83  data->row = src.row;
84  data->preferred_width = src.preferred_width;
86  }
87 
88 
91  {
93  (
94  lrtd.left,
95  lrtd.right,
96  lrtd.top,
97  lrtd.bottom
98  );
99  }
100 
101 
102  std::shared_ptr<Widget>
104  (
105  io::FileSystem* fs,
106  State* state,
107  const files::gui::Widget& w,
108  render::TextureCache* cache,
109  const std::map<std::string, Skin*>& skins
110  )
111  {
112  std::shared_ptr<Widget> ret;
113 
114  if(w.button)
115  {
116  auto b = std::make_shared<CommandButton>(state);
117 
118  const std::string skin_name = w.button->skin;
119  const auto skin_it = skins.find(skin_name);
120  Skin* skin = nullptr;
121 
122  if(skin_it == skins.end())
123  {
124  LOG_ERROR("Failed to find skin '{0}'", skin_name);
125  }
126  else
127  {
128  b->set_skin(skin_it->second);
129 
130  skin = skin_it->second;
131 
132  if(skin_it->second->button_image.has_value())
133  {
134  std::shared_ptr<render::ScalableSprite> sp
135  {
137  {
138  fs,
139  skin->button_image.value(),
140  cache
141  }
142  };
143  b->sprite = sp;
144  }
145  }
146  ret = b;
147  b->cmd = w.button->command;
148  b->text.update_string(w.button->text);
149 
150  if(skin != nullptr)
151  {
152  b->text.set_font(skin->font);
153  }
154  }
155  else if(w.panel)
156  {
157  auto l = std::make_shared<PanelWidget>(state);
158  ret = l;
160  (
161  fs,
162  state,
163  &l->container,
164  w.panel->container,
165  cache,
166  skins
167  );
168  }
169  else
170  {
171  LOG_ERROR("Invalid widget");
172  }
173 
174  ASSERT(ret);
175 
176  // load basic widget data
177  ret->name = w.name;
178  ret->padding = from_gaf_to_lrud(w.padding);
179  ret->margin = from_gaf_to_lrud(w.margin);
180 
181  setup_layout(&ret->layout, w);
182 
183  return ret;
184  }
185 
186  void
188  (
189  io::FileSystem* fs,
190  State* state,
191  LayoutContainer* root,
193  render::TextureCache* cache,
194  const std::map<std::string, Skin*>& skins
195  )
196  {
197  root->layout = create_layout(c.layout);
198  for(const auto& widget: c.widgets)
199  {
200  root->add(create_widget(fs, state, widget, cache, skins));
201  }
202  }
203 
204  Rgb
205  load(const files::gui::Rgb& src)
206  {
207  return {src.r, src.g, src.b};
208  }
209 
212  {
213  switch(t)
214  {
215 #define FUN(NAME) \
216  case files::gui::InterpolationType::NAME: return core::easing::Function::NAME;
217  FUN(linear)
218  FUN(smooth_start2)
219  FUN(smooth_start3)
220  FUN(smooth_start4)
221  FUN(smooth_stop2)
222  FUN(smooth_stop3)
223  FUN(smooth_stop4)
224  FUN(smooth_step2)
225  FUN(smooth_step3)
226  FUN(smooth_step4)
227 #undef FUN
228  default: return core::easing::Function::linear;
229  }
230  }
231 
232 
233  ButtonState
235  {
236  ButtonState ret;
237  // ret.image = src.image();
238  ret.scale = src.scale;
239  ret.image_color = load(src.image_color);
240  ret.text_color = load(src.text_color);
241  ret.dx = src.dx;
242  ret.dy = src.dy;
243  ret.interpolation_color =
244  {
245  load(src.interpolate_color),
247  };
248  ret.interpolation_size =
249  {
250  load(src.interpolate_size),
252  };
254  {
257  };
258  return ret;
259  }
260 
261 
262  std::shared_ptr<Skin>
263  load_skin(const files::gui::Skin& src, render::FontCache* font, const io::DirPath& folder)
264  {
265  std::shared_ptr<Skin> skin(new gui::Skin());
266  skin->name = src.name;
267 
268  const auto relative_font_file = io::FilePath::from_script(src.font).value_or
269  (
270  io::FilePath{ "~/invalid_font_file" }
271  );
272  const auto resolved_font_file = io::resolve_relative(relative_font_file, folder);
273  if(resolved_font_file)
274  {
275  skin->font = font->get_font
276  (
277  *resolved_font_file
278  );
279  }
280  else
281  {
282  LOG_ERROR("Unable to resolve font file {} for skin {}", relative_font_file, src.name);
283  }
284 
285  if (const auto relative_image_file = io::FilePath::from_script_or_empty(src.button_image); relative_image_file)
286  {
287  const auto resolved_file = io::resolve_relative(*relative_image_file, folder);
288  if (resolved_file)
289  {
290  skin->button_image = *resolved_file;
291  }
292  else
293  {
294  LOG_ERROR("Unable to resolve button image {} for skin {}", *relative_image_file, src.name);
295  }
296  }
297 
298  skin->text_size = src.text_size;
299  skin->button_idle = load_button(src.button_idle);
300  skin->button_hot = load_button(src.button_hot);
301  skin->button_active_hot = load_button(src.button_active_hot);
302  return skin;
303  }
304 
305 
306  bool
308  (
309  Root* root,
310  io::FileSystem* fs,
311  render::FontCache* font,
312  const io::FilePath& path,
313  render::TextureCache* cache
314  )
315  {
317 
318  if (const auto loaded = io::read_json_file(fs, path); loaded == false)
319  {
320  LOG_ERROR("Failed to load {}: {}", path, loaded.get_error().display);
321  return false;
322  }
323  else
324  {
325  const auto& json = loaded.get_value();
326  const auto parsed = files::gui::parse(log::get_global_logger(), &f, json.root, &json.doc);
327  if (!parsed)
328  {
329  return false;
330  }
331  }
332 
333  const auto folder = path.get_directory();
334 
335  if(auto relative = io::FilePath::from_script_or_empty(f.cursor_image); relative)
336  {
337  const auto resolved = io::resolve_relative(*relative, folder);
338  if (resolved)
339  {
340  root->cursor_image = cache->get_texture(*resolved);
341  }
342  else
343  {
344  LOG_ERROR("Invalid path for cursor_image: {}", *relative);
345  }
346  }
347 
348  if (auto relative = io::FilePath::from_script_or_empty(f.hover_image); relative)
349  {
350  const auto resolved = io::resolve_relative(*relative, folder);
351  if (resolved)
352  {
353  root->hover_image = cache->get_texture(*resolved);
354  }
355  else
356  {
357  LOG_ERROR("Invalid path for hover_image: {}", *relative);
358  }
359  }
360 
361  std::map<std::string, Skin*> skin_map;
362 
363  for(const auto& skin: f.skins)
364  {
365  std::shared_ptr<gui::Skin> skin_ptr = load_skin(skin, font, folder);
366  skin_map.insert(std::make_pair(skin.name, skin_ptr.get()));
367  root->skins.push_back(skin_ptr);
368  }
369 
371  (
372  fs,
373  &root->state,
374  &root->container,
375  f.root,
376  cache,
377  skin_map
378  );
379 
380  return root->container.has_any_widgets();
381  }
382 }
#define ASSERT(x)
Definition: assert.h:29
#define FUN(NAME)
#define LOG_INFO(...)
Definition: log.h:7
#define LOG_ERROR(...)
Definition: log.h:9
InterpolationType
Definition: gui.h:8
void setup_layout(LayoutData *data, const files::gui::Widget &src)
Definition: load.cc:80
bool load_gui(Root *root, io::FileSystem *fs, render::FontCache *font, const io::FilePath &path, render::TextureCache *cache)
Definition: load.cc:308
std::shared_ptr< Layout > create_single_row_layout(float padding)
void build_layout_container(io::FileSystem *fs, State *state, LayoutContainer *root, const files::gui::LayoutContainer &c, render::TextureCache *cache, const std::map< std::string, Skin * > &skins)
Definition: load.cc:188
std::shared_ptr< Skin > load_skin(const files::gui::Skin &src, render::FontCache *font, const io::DirPath &folder)
Definition: load.cc:263
ButtonState load_button(const files::gui::ButtonState &src)
Definition: load.cc:234
std::shared_ptr< Layout > create_table_layout(const std::vector< bool > &expandable_rows, const std::vector< bool > &expandable_cols, float combined_padding)
Rgb load(const files::gui::Rgb &src)
Definition: load.cc:205
std::shared_ptr< Layout > create_layout(const files::gui::Layout &c)
Definition: load.cc:26
std::shared_ptr< Widget > create_widget(io::FileSystem *fs, State *state, const files::gui::Widget &w, render::TextureCache *cache, const std::map< std::string, Skin * > &skins)
Definition: load.cc:104
Lrud< float > from_gaf_to_lrud(const files::gui::Lrtb &lrtd)
Definition: load.cc:90
JsonResult read_json_file(FileSystem *fs, const FilePath &file_name)
Definition: json.cc:58
std::optional< DirPath > resolve_relative(const DirPath &base)
Definition: vfs_path.cc:349
Logger * get_global_logger()
Definition: log.cc:34
static Self from_lrud(const T &lr, const T &ud)
Create a new fourway from left-righ and up-down.
Definition: lrud.h:41
Definition: rgb.h:62
InterpolationType interpolate_color
Definition: gui.h:120
float interpolate_position_time
Definition: gui.h:118
float interpolate_color_time
Definition: gui.h:121
InterpolationType interpolate_size
Definition: gui.h:123
InterpolationType interpolate_position
Definition: gui.h:117
float bottom
Definition: gui.h:51
float text_size
Definition: gui.h:131
std::string button_image
Definition: gui.h:132
ButtonState button_idle
Definition: gui.h:134
std::string font
Definition: gui.h:130
ButtonState button_active_hot
Definition: gui.h:136
std::string name
Definition: gui.h:129
ButtonState button_hot
Definition: gui.h:135
float preferred_width
Definition: gui.h:61
float preferred_height
Definition: gui.h:62
Interpolation interpolation_color
Definition: skin.h:34
Interpolation interpolation_size
Definition: skin.h:35
Interpolation interpolation_position
Definition: skin.h:33
CommandButton(gui::State *state)
Definition: load.cc:51
std::string cmd
Definition: load.cc:63
void on_clicked() override
Definition: load.cc:57
bool has_any_widgets() const
Definition: container.cc:15
void add(std::shared_ptr< Widget > widget)
Definition: container.cc:22
std::shared_ptr< gui::Layout > layout
std::shared_ptr< render::Texture2 > hover_image
Definition: root.h:71
State state
Definition: root.h:68
std::vector< std::shared_ptr< Skin > > skins
Definition: root.h:66
LayoutContainer container
Definition: root.h:69
std::shared_ptr< render::Texture2 > cursor_image
Definition: root.h:70
std::shared_ptr< render::DrawableFont > font
Definition: skin.h:51
std::optional< io::FilePath > button_image
Definition: skin.h:55
static std::optional< FilePath > from_script_or_empty(const std::string &path)
optional or not, log if error
Definition: vfs_path.cc:102
DirPath get_directory() const
Definition: vfs_path.cc:137
static std::optional< FilePath > from_script(const std::string &path)
apply only minor changes, return null on invalid
Definition: vfs_path.cc:46
std::shared_ptr< DrawableFont > get_font(const io::FilePath &path) const
Definition: fontcache.cc:41
std::shared_ptr< Texture2 > get_texture(const io::FilePath &path) const
Definition: texturecache.cc:47
ParserState state
Definition: ui_text.cc:134