~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to library/forms/gtk/src/lf_code_editor.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "../lf_mforms.h"
 
2
 
 
3
#include "base/string_utilities.h"
 
4
#include "../lf_code_editor.h"
 
5
#include "tinyxml.h"
 
6
#include <memory>
 
7
#include <ctype.h>
 
8
#include <stdlib.h>
 
9
#include "base/wb_memory.h"
 
10
#include "base/wb_iterators.h"
 
11
 
 
12
#include "Scintilla.h"
 
13
#include "SciLexer.h"
 
14
#define PLAT_GTK 2
 
15
#define GTK
 
16
#include "ScintillaWidget.h"
 
17
 
 
18
// Marker ID assignments. Markers with higher number overlay lower ones.
 
19
#define CE_STATEMENT_MARKER 0
 
20
#define CE_ERROR_MARKER 1
 
21
#define CE_BREAKPOINT_MARKER 2
 
22
#define CE_BREAKPOINT_HIT_MARKER 3
 
23
#define CE_CURRENT_LINE_MARKER 3
 
24
 
 
25
bool string_to_bool(const std::string& value)
 
26
{
 
27
  const std::string v = base::tolower(value);
 
28
  return v == "1" || v == "true" || v == "yes";
 
29
}
 
30
 
 
31
int string_to_int(const std::string& v, const int base = 10)
 
32
{
 
33
  char *end = 0;
 
34
  const char* start = v.c_str();
 
35
  int ret = strtoll(start, &end, base);
 
36
  if (!( !*end && end != start))
 
37
    ret = 0;
 
38
 
 
39
  return ret;
 
40
}
 
41
 
 
42
int str_color_to_int(const std::string& v)
 
43
{
 
44
  int ret = 0;
 
45
  size_t len = v.length();
 
46
  if (len >= 7)
 
47
  {
 
48
    size_t pos = v.find("#");
 
49
    if (pos != std::string::npos && (pos + 7) <= len)
 
50
    {
 
51
      ret = string_to_int(v.substr(pos + 1, 6), 16);
 
52
    }
 
53
  }
 
54
  return ret;
 
55
}
 
56
 
 
57
//==============================================================================
 
58
 
 
59
 
 
60
//==============================================================================
 
61
//
 
62
//==============================================================================
 
63
//------------------------------------------------------------------------------
 
64
 
 
65
 
 
66
static void notify_signal(GtkWidget *w, gint wParam, gpointer lParam, mforms::gtk::CodeEditorImpl *editor)
 
67
{
 
68
    SCNotification *event = reinterpret_cast<SCNotification *>(lParam);
 
69
    editor->notify(event);
 
70
}
 
71
 
 
72
mforms::gtk::CodeEditorImpl::CodeEditorImpl(CodeEditor* self)
 
73
       : ViewImpl(self)
 
74
       ,_sci_gtk_widget(0)
 
75
       ,_sci_gtkmm_widget(0)
 
76
       ,_sci(0)
 
77
{
 
78
  _sci_gtk_widget = scintilla_new();
 
79
  _sci_gtkmm_widget = Glib::wrap(_sci_gtk_widget);
 
80
  _sci = SCINTILLA(_sci_gtk_widget);
 
81
  _owner = self;
 
82
  gtk_signal_connect(GTK_OBJECT(_sci_gtk_widget), SCINTILLA_NOTIFY, GTK_SIGNAL_FUNC(notify_signal), this);
 
83
  _sci_gtkmm_widget->show();
 
84
}
 
85
 
 
86
//------------------------------------------------------------------------------
 
87
mforms::gtk::CodeEditorImpl::~CodeEditorImpl()
 
88
{}
 
89
 
 
90
//------------------------------------------------------------------------------
 
91
Gtk::Widget *mforms::gtk::CodeEditorImpl::get_outer() const
 
92
{
 
93
  return _sci_gtkmm_widget;
 
94
}
 
95
 
 
96
//--------------------------------------------------------------------------------------------------
 
97
/**
 
98
 * This function loads the style name map from an external file which allows us to map
 
99
 * style names to their associated ids.
 
100
 */
 
101
static void load_style_names(const std::string path, mforms::gtk::StyleNameMap *map)
 
102
{
 
103
  base::FILE_scope_ptr fp = fopen(path.c_str(), "r");
 
104
 
 
105
  if (fp)
 
106
  {
 
107
    int c = EOF;
 
108
    std::string name(256, ' ');
 
109
    std::string value(256, ' ');
 
110
 
 
111
    name = value = "";
 
112
 
 
113
    std::string *cur = &name;
 
114
    do
 
115
    {
 
116
      c = getc(fp);
 
117
      switch (c)
 
118
      {
 
119
        case '\n':
 
120
        case EOF:
 
121
          {
 
122
            if (name.length() > 0 && value.length() > 0)
 
123
            {
 
124
              char *end = 0;
 
125
              const char* start = value.c_str();
 
126
              const int style_id = strtoll(start, &end, 10);
 
127
              if ( !*end && end != start)
 
128
              {
 
129
                (*map)[name] = style_id;
 
130
              }
 
131
            }
 
132
            name.clear();
 
133
            value.clear();
 
134
            cur = &name;
 
135
            break;
 
136
          }
 
137
        case '=':
 
138
          {
 
139
            cur = &value;
 
140
            break;
 
141
          }
 
142
        default:
 
143
          {
 
144
            if (isalnum(c) || c == '_')
 
145
              cur->append(1, c);
 
146
          }
 
147
      }
 
148
    }
 
149
    while (c != EOF);
 
150
    }
 
151
}
 
152
 
 
153
//--------------------------------------------------------------------------------------------------
 
154
/**
 
155
 * Superordinated style map loader which controls the load_style_names function.
 
156
 */
 
157
static mforms::gtk::StyleNameMap get_style_map(const std::string& language)
 
158
{
 
159
  mforms::gtk::StyleNameMap ret;
 
160
 
 
161
  // These are global styles and always available.
 
162
  ret["BRACEBAD"]    = STYLE_BRACEBAD;
 
163
  ret["BRACELIGHT"]  = STYLE_BRACELIGHT;
 
164
  ret["CALLTIP"]     = STYLE_CALLTIP;
 
165
  ret["CONTROLCHAR"] = STYLE_CONTROLCHAR;
 
166
  ret["DEFAULT"]     = STYLE_DEFAULT;
 
167
  ret["LINENUMBER"]  = STYLE_LINENUMBER;
 
168
 
 
169
  load_style_names(mforms::App::get()->get_resource_path("default.txt"), &ret);
 
170
  if (language != "Null")
 
171
  {
 
172
    load_style_names(mforms::App::get()->get_resource_path(language + ".txt"), &ret);
 
173
  }
 
174
 
 
175
  return ret;
 
176
}
 
177
 
 
178
//--------------------------------------------------------------------------------------------------
 
179
/**
 
180
 * Loads the configuration file for the given language and fills the given style map with the loaded
 
181
 * style data. Every other setting (tab usage, keywords etc.) will be applied
 
182
 * to the editor on the way. Styles need a bit more processing so the caller will take for that.
 
183
 */
 
184
void mforms::gtk::CodeEditorImpl::load_language_settings(const std::string& language, mforms::gtk::CodeEditorImpl::StyleMap &sm)
 
185
{
 
186
  const std::string config_file_path = mforms::App::get()->get_resource_path(language + ".xml");
 
187
  TiXmlDocument doc(config_file_path);
 
188
  if (!doc.LoadFile())
 
189
  {
 
190
    // TODO: Print error and exit load_language_settings
 
191
    return;
 
192
  }
 
193
  else
 
194
  {
 
195
    TiXmlHandle hdoc(&doc);
 
196
    TiXmlHandle root(0);
 
197
 
 
198
    // Check that we loaded correct xml file
 
199
    TiXmlElement *pel = hdoc.FirstChildElement().Element();
 
200
    if (pel->ValueStr() != "ScintillaNET")
 
201
    {
 
202
      fprintf(stderr, "Error, root xml node is not correct\n");
 
203
    }
 
204
    root = TiXmlHandle(pel);
 
205
 
 
206
    // Locate child node Language with Name attribute equal to language
 
207
    pel = root.FirstChild("Language").Element();
 
208
    TiXmlElement *lang_el(0);
 
209
    for (; pel; pel=pel->NextSiblingElement())
 
210
    {
 
211
      if (pel->Attribute("Name") == language)
 
212
      {
 
213
        lang_el = pel;
 
214
        break;
 
215
      }
 
216
    }
 
217
 
 
218
    if (lang_el)
 
219
    {
 
220
      //parse Indentation
 
221
      TiXmlElement *child = lang_el->FirstChildElement("Indentation");
 
222
      if (child)
 
223
      {
 
224
        const char* attr = child->Attribute("TabWidth");
 
225
        if (attr)
 
226
          send_editor(SCI_SETTABWIDTH, atoi(attr));
 
227
        attr = child->Attribute("UseSpaces");
 
228
        if (attr)
 
229
          send_editor(SCI_SETUSETABS, bool(atoi(attr)));
 
230
      }
 
231
 
 
232
      // Parse lexer
 
233
      child = lang_el->FirstChildElement("Lexer");
 
234
      if (child)
 
235
      {
 
236
        TiXmlElement *lex_child = child->FirstChildElement("Keywords");
 
237
        int list_id = 0;
 
238
        const char *kw_list = 0;
 
239
        for (; lex_child; lex_child = lex_child->NextSiblingElement("Keywords"))
 
240
        {
 
241
          if (TIXML_SUCCESS != lex_child->QueryIntAttribute("List", &list_id))
 
242
            list_id = 0;
 
243
          kw_list = lex_child->GetText();
 
244
          if (kw_list)
 
245
          {
 
246
            send_editor(SCI_SETKEYWORDS, list_id, (sptr_t)kw_list);
 
247
          }
 
248
        }
 
249
 
 
250
        lex_child = child->FirstChildElement("Properties");
 
251
        for (; lex_child; lex_child = lex_child->NextSiblingElement("Properties"))
 
252
        {
 
253
          TiXmlElement *prop = lex_child->FirstChildElement("Property");
 
254
          const char* name  = 0;
 
255
          const char* value = 0;
 
256
          for(; prop; prop = prop->NextSiblingElement("Property"))
 
257
          {
 
258
            name  = prop->Attribute("Name");
 
259
            value = prop->Attribute("Value");
 
260
            if (name && value && strlen(name) > 0 && strlen(value) > 0)
 
261
              send_editor(SCI_SETPROPERTY, (uptr_t)name, (sptr_t)value);
 
262
          }
 
263
        }
 
264
      }
 
265
 
 
266
      // Parse styles
 
267
      TiXmlElement* style       = 0;
 
268
      const char*   name        = 0;
 
269
      const char*   value       = 0;
 
270
      StyleNameMap  style_names = get_style_map(language);
 
271
 
 
272
      child = lang_el->FirstChildElement("Styles");
 
273
      for(; child; child = child->NextSiblingElement())
 
274
      {
 
275
        style = child->FirstChildElement("Style");
 
276
        for (; style; style = style->NextSiblingElement("Style"))
 
277
        {
 
278
          name = style->Attribute("Name");
 
279
          int style_id = -1;
 
280
          if (name)
 
281
          {
 
282
            StyleNameMap::iterator name_it = style_names.find(name);
 
283
            if (name_it != style_names.end())
 
284
              style_id = name_it->second;
 
285
          }
 
286
 
 
287
          if (style_id >= 0)
 
288
          {
 
289
            std::string style_entry;
 
290
            StyleMap::mapped_type &dict_for_style = sm[style_id];
 
291
 
 
292
            // Number and correspondence of items must be maintained!
 
293
            static const char *tags[] = {"ForeColor", "BackColor", "Bold", "FontName", "Italic", "Size", "Underline", 0};
 
294
            static const int tag_id[] = {SCI_STYLESETFORE, SCI_STYLESETBACK, SCI_STYLESETBOLD, SCI_STYLESETFONT, SCI_STYLESETITALIC, SCI_STYLESETSIZE, SCI_STYLESETUNDERLINE, 0};
 
295
 
 
296
            const int* ptag_id = tag_id;
 
297
            for (const char** t = tags; *t; ++t, ++ptag_id)
 
298
            {
 
299
              if (TIXML_SUCCESS == style->QueryStringAttribute(*t, &style_entry))
 
300
                dict_for_style[*tag_id] = style_entry;
 
301
            }
 
302
          }
 
303
        } // for (; style; style = style->NextSiblingElement("Style"))
 
304
      } // for(; child; child = child->NextSiblingElement())
 
305
    } // if (lang_el)
 
306
  }
 
307
}
 
308
 
 
309
//--------------------------------------------------------------------------------------------------
 
310
 
 
311
void mforms::gtk::CodeEditorImpl::language_setup(const std::string& language)
 
312
{
 
313
  // In opposition to the Windows version of this implementation we do not have automatic language
 
314
  // setup, so we have to take care for keywords and colors manually here.
 
315
  send_editor(SCI_SETLEXERLANGUAGE, 0, (sptr_t)language.c_str());
 
316
 
 
317
  StyleMap map;
 
318
  load_language_settings("default", map);
 
319
  if (language != "Null")
 
320
  {
 
321
    load_language_settings(language, map);
 
322
  }
 
323
 
 
324
  // Here we have styles loaded
 
325
  int style_id = 0;
 
326
  for (base::const_range<StyleMap> style(map); style; ++style)
 
327
  {
 
328
    style_id = style->first;
 
329
    int property = 0;
 
330
    std::string value;
 
331
 
 
332
    const StyleMap::mapped_type &style_traits = style->second;
 
333
    for (base::const_range<StyleMap::mapped_type> trait(style_traits); trait; ++trait)
 
334
    {
 
335
      property = trait->first;
 
336
      value    = trait->second;
 
337
 
 
338
      switch (property)
 
339
      {
 
340
        case SCI_STYLESETFORE:
 
341
        case SCI_STYLESETBACK:
 
342
          send_editor(property, style_id, str_color_to_int(value));
 
343
          break;
 
344
 
 
345
        case SCI_STYLESETFONT:
 
346
          send_editor(property, style_id, (sptr_t)value.c_str());
 
347
          break;
 
348
 
 
349
        case SCI_STYLESETBOLD:
 
350
        case SCI_STYLESETITALIC:
 
351
        case SCI_STYLESETUNDERLINE:
 
352
          send_editor(property, style_id, string_to_bool(value));
 
353
          break;
 
354
 
 
355
        case SCI_STYLESETSIZE:
 
356
          send_editor(property, style_id, string_to_int(value));
 
357
          break;
 
358
      }
 
359
    }
 
360
  }
 
361
}
 
362
 
 
363
//------------------------------------------------------------------------------
 
364
void mforms::gtk::CodeEditorImpl::setup_marker(const int marker_id, const char* icon_path, int background)
 
365
{
 
366
  const std::string     full_path = mforms::App::get()->get_resource_path(icon_path);
 
367
  base::FILE_scope_ptr  fp        = fopen(full_path.c_str(), "r");
 
368
  base::AutoCharArray   xpm(0);
 
369
 
 
370
  if (fp)
 
371
  {
 
372
    fseek(fp,0,SEEK_END);
 
373
    const long size = ftell(fp);
 
374
    fseek(fp,0,SEEK_SET);
 
375
    if (size > 0)
 
376
    {
 
377
      xpm = base::AutoCharArray(new char[size]);
 
378
      long items_read = fread(xpm.get(), 1, size, fp);
 
379
      // TODO: Check for EINTR and ENOMEM
 
380
      if (items_read != size)
 
381
        xpm = base::AutoCharArray();
 
382
    }
 
383
  }
 
384
 
 
385
  if (!xpm.get())
 
386
  {
 
387
    send_editor(SCI_MARKERDEFINE, marker_id, SC_MARK_BACKGROUND);
 
388
    send_editor(SCI_MARKERSETBACK, marker_id, background);
 
389
    send_editor(SCI_MARKERSETFORE, marker_id, 0xffffff);
 
390
  }
 
391
  else
 
392
    send_editor(SCI_MARKERDEFINEPIXMAP, marker_id, (sptr_t)xpm.get());
 
393
}
 
394
 
 
395
//------------------------------------------------------------------------------
 
396
void mforms::gtk::CodeEditorImpl::setup_editor(const bool use_tabs, const int indentation, const std::string& lang)
 
397
{
 
398
  // Some values as default before reading the config file.
 
399
  send_editor(SCI_SETUSETABS, use_tabs ? 1 : 0);
 
400
  send_editor(SCI_SETTABWIDTH, indentation);
 
401
  send_editor(SCI_SETTABINDENTS, 1);
 
402
  send_editor(SCI_SETINDENT, indentation);
 
403
 
 
404
  language_setup(lang);
 
405
 
 
406
  send_editor(SCI_SETCARETLINEVISIBLE, 1);
 
407
  send_editor(SCI_SETCARETLINEBACK, 0xF8C800);
 
408
  send_editor(SCI_SETCARETLINEBACKALPHA, 20);
 
409
 
 
410
  send_editor(SCI_SETBACKSPACEUNINDENTS, 1);
 
411
  const int guide_type = (lang == "python") ? SC_IV_LOOKFORWARD : SC_IV_LOOKBOTH;
 
412
  send_editor(SCI_SETINDENTATIONGUIDES, guide_type);
 
413
 
 
414
  // Margin: Line number style.
 
415
  send_editor(SCI_STYLESETFORE, STYLE_LINENUMBER, 0x404040);
 
416
  send_editor(SCI_STYLESETBACK, STYLE_LINENUMBER, 0xE0E0E0);
 
417
 
 
418
  send_editor(SCI_SETMARGINTYPEN, 0, SC_MARGIN_NUMBER);
 
419
  const int lineNumberStyleWidth = send_editor(SCI_TEXTWIDTH, STYLE_LINENUMBER, (sptr_t)"_99999");
 
420
  send_editor(SCI_SETMARGINWIDTHN, 0, lineNumberStyleWidth);
 
421
  send_editor(SCI_SETMARGINSENSITIVEN, 0, 1); // Make Scintilla send a notification for clicks in this margin.
 
422
 
 
423
  // Margin: Markers.
 
424
  send_editor(SCI_SETMARGINWIDTHN, 1, 16);
 
425
  send_editor(SCI_SETMARGINSENSITIVEN, 1, 1);
 
426
  
 
427
  // Margin: Indicators (folders).
 
428
  send_editor(SCI_SETFOLDMARGINCOLOUR, 1, 0xE6E6E6);
 
429
  send_editor(SCI_SETMARGINWIDTHN, 2, 16);
 
430
  send_editor(SCI_SETMARGINSENSITIVEN, 2, 1);
 
431
  
 
432
  send_editor(SCI_SETEOLMODE, SC_EOL_LF);
 
433
 
 
434
  // Marker definitions.
 
435
  setup_marker(CE_STATEMENT_MARKER, "editor_statement.xpm", 0x0000ff);
 
436
  setup_marker(CE_ERROR_MARKER, "editor_error.xpm", 0x32de2e);
 
437
  setup_marker(CE_BREAKPOINT_MARKER, "editor_breakpoint.xpm", 0xa9443e);
 
438
  setup_marker(CE_BREAKPOINT_HIT_MARKER, "editor_breakpoint_hit.xpm", 0xa9443e);
 
439
  setup_marker(CE_CURRENT_LINE_MARKER, "editor_current_pos.xpm", 0xa9443e);
 
440
 
 
441
  // Folder setup.
 
442
  send_editor(SCI_SETMARGINWIDTHN, 2, 16);
 
443
  send_editor(SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS);
 
444
  send_editor(SCI_SETMARGINSENSITIVEN, 2, 1);
 
445
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
 
446
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
 
447
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
 
448
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
 
449
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
 
450
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
 
451
  send_editor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
 
452
  for (int n= 25; n < 32; ++n) // Markers 25..31 are reserved for folding.
 
453
  {
 
454
    send_editor(SCI_MARKERSETFORE, n, 0xffffff);
 
455
    send_editor(SCI_MARKERSETBACK, n, 0x404040);
 
456
  }
 
457
  
 
458
  // Init markers & indicators for highlighting of syntax errors.
 
459
  send_editor(SCI_INDICSETFORE, 0, 0xD01921);
 
460
  send_editor(SCI_INDICSETUNDER, 0, 1);
 
461
  send_editor(SCI_INDICSETSTYLE, 0, INDIC_SQUIGGLE);
 
462
}
 
463
 
 
464
//------------------------------------------------------------------------------
 
465
bool mforms::gtk::CodeEditorImpl::create(CodeEditor* self)
 
466
{
 
467
  return new mforms::gtk::CodeEditorImpl(self);
 
468
}
 
469
 
 
470
//------------------------------------------------------------------------------
 
471
void mforms::gtk::CodeEditorImpl::set_text(CodeEditor* self, const std::string& text)
 
472
{
 
473
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
474
 
 
475
  const int pos = ce->send_editor(SCI_GETCURRENTPOS);
 
476
  ce->send_editor(SCI_SETTEXT, 0, (sptr_t)text.c_str());
 
477
  ce->send_editor(SCI_GOTOPOS, pos);
 
478
  ce->send_editor(SCI_SCROLLCARET);
 
479
}
 
480
 
 
481
//------------------------------------------------------------------------------
 
482
const std::string mforms::gtk::CodeEditorImpl::get_text(CodeEditor* self, bool selection_only)
 
483
{
 
484
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
485
 
 
486
  char *buffer(0);
 
487
  const int length = ce->send_editor(SCI_GETLENGTH);
 
488
  if ( length > 0 )
 
489
  {
 
490
    buffer = new char[length+1];
 
491
    try
 
492
    {
 
493
      ce->send_editor(SCI_GETTEXT, length+1, (sptr_t)buffer);
 
494
      //send_editor(SCI_SETSAVEPOINT); // TODO: Check if we should tell sci that document is unmodified
 
495
    }
 
496
    catch (...)
 
497
    {
 
498
      delete[] buffer;
 
499
      buffer = 0;
 
500
    }
 
501
  }
 
502
 
 
503
  const std::string ret = buffer ? buffer : "";
 
504
  delete[] buffer;
 
505
  return ret;
 
506
}
 
507
 
 
508
//------------------------------------------------------------------------------
 
509
void mforms::gtk::CodeEditorImpl::get_selection(CodeEditor* self, int &start, int &length)
 
510
{
 
511
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
512
 
 
513
  start  = ce->send_editor(SCI_GETSELECTIONSTART);
 
514
  length = ce->send_editor(SCI_GETSELECTIONEND);
 
515
}
 
516
 
 
517
//------------------------------------------------------------------------------
 
518
void mforms::gtk::CodeEditorImpl::set_selection(CodeEditor* self, int start, int length)
 
519
{
 
520
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
521
 
 
522
  ce->send_editor(SCI_SETSELECTIONSTART, start);
 
523
  ce->send_editor(SCI_SETSELECTIONEND, start + length);
 
524
}
 
525
 
 
526
//------------------------------------------------------------------------------
 
527
bool mforms::gtk::CodeEditorImpl::get_range_of_line(CodeEditor* self, int line, int &start, int &length)
 
528
{
 
529
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
530
 
 
531
  const int lstart  = ce->send_editor(SCI_POSITIONFROMLINE, line);
 
532
  if (lstart >= 0)
 
533
    start = lstart;
 
534
  length = ce->send_editor(SCI_LINELENGTH, line);
 
535
 
 
536
  return lstart >= 0;
 
537
}
 
538
 
 
539
//------------------------------------------------------------------------------
 
540
void mforms::gtk::CodeEditorImpl::set_language(CodeEditor* self, SyntaxHighlighterLanguage language)
 
541
{
 
542
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
543
 
 
544
  if (ce)
 
545
  {
 
546
    switch (language)
 
547
    {
 
548
      case mforms::LanguageCpp:
 
549
        ce->setup_editor(false, 2, "cpp"); // Currently string based. Will later use enum.
 
550
        break;
 
551
 
 
552
      case mforms::LanguageLua:
 
553
        ce->setup_editor(true, 4, "lua");
 
554
        break;
 
555
 
 
556
      case mforms::LanguagePython:
 
557
        ce->setup_editor(true, 4, "python");
 
558
        break;
 
559
 
 
560
      case mforms::LanguageMySQL:
 
561
        ce->setup_editor(false, 2, "mysql");
 
562
        break;
 
563
 
 
564
      default:
 
565
        ce->setup_editor(false, 2, "Null");
 
566
    }
 
567
  }
 
568
}
 
569
 
 
570
//------------------------------------------------------------------------------
 
571
void mforms::gtk::CodeEditorImpl::set_read_only(CodeEditor* self, bool flag)
 
572
{
 
573
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
574
  if (ce)
 
575
  {
 
576
    ce->send_editor(SCI_SETREADONLY, flag);
 
577
  }
 
578
}
 
579
 
 
580
//------------------------------------------------------------------------------
 
581
void mforms::gtk::CodeEditorImpl::show_markup(CodeEditor* self, LineMarkup markup, int line)
 
582
{
 
583
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
584
  if (ce)
 
585
  {
 
586
    // The marker mask contains one bit for each set marker (0..31).
 
587
    unsigned int marker_mask = ce->send_editor(SCI_MARKERGET, line);
 
588
    unsigned int new_marker_mask = 0;
 
589
    if ((markup & mforms::LineMarkupStatement) != 0)
 
590
    {
 
591
      unsigned int mask = 1 << CE_STATEMENT_MARKER;
 
592
      if ((marker_mask & mask) != mask)
 
593
        new_marker_mask |= mask;
 
594
    }
 
595
    if ((markup & mforms::LineMarkupError) != 0)
 
596
    {
 
597
      unsigned int mask = 1 << CE_ERROR_MARKER;
 
598
      if ((marker_mask & mask) != mask)
 
599
        new_marker_mask |= mask;
 
600
    }
 
601
    if ((markup & mforms::LineMarkupBreakpoint) != 0)
 
602
    {
 
603
      unsigned int mask = 1 << CE_BREAKPOINT_MARKER;
 
604
      if ((marker_mask & mask) != mask)
 
605
        new_marker_mask |= mask;
 
606
    }
 
607
    if ((markup & mforms::LineMarkupBreakpointHit) != 0)
 
608
    {
 
609
      unsigned int mask = 1 << CE_BREAKPOINT_HIT_MARKER;
 
610
      if ((marker_mask & mask) != mask)
 
611
        new_marker_mask |= mask;
 
612
    }
 
613
    if ((markup & mforms::LineMarkupCurrent) != 0)
 
614
    {
 
615
      unsigned int mask = 1 << CE_CURRENT_LINE_MARKER;
 
616
      if ((marker_mask & mask) != mask)
 
617
        new_marker_mask |= mask;
 
618
    }
 
619
 
 
620
    ce->send_editor(SCI_MARKERADDSET, line, new_marker_mask);
 
621
  }
 
622
}
 
623
 
 
624
//------------------------------------------------------------------------------
 
625
void mforms::gtk::CodeEditorImpl::remove_markup(CodeEditor* self, LineMarkup markup, int line)
 
626
{
 
627
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
628
  if (ce)
 
629
  {
 
630
    if (markup == mforms::LineMarkupAll)
 
631
      ce->send_editor(SCI_MARKERDELETEALL, line);
 
632
    else
 
633
    {
 
634
      if ((markup & mforms::LineMarkupStatement) != 0)
 
635
        ce->send_editor(SCI_MARKERDELETE, line, CE_STATEMENT_MARKER);
 
636
      if ((markup & mforms::LineMarkupError) != 0)
 
637
        ce->send_editor(SCI_MARKERDELETE, line, CE_ERROR_MARKER);
 
638
      if ((markup & mforms::LineMarkupBreakpoint) != 0)
 
639
        ce->send_editor(SCI_MARKERDELETE, line, CE_BREAKPOINT_MARKER);
 
640
      if ((markup & mforms::LineMarkupBreakpointHit) != 0)
 
641
        ce->send_editor(SCI_MARKERDELETE, line, CE_BREAKPOINT_HIT_MARKER);
 
642
      if ((markup & mforms::LineMarkupCurrent) != 0)
 
643
        ce->send_editor(SCI_MARKERDELETE, line, CE_CURRENT_LINE_MARKER);
 
644
    }
 
645
  }
 
646
}
 
647
 
 
648
//------------------------------------------------------------------------------
 
649
int mforms::gtk::CodeEditorImpl::line_count(CodeEditor* self)
 
650
{
 
651
  int ret = 0;
 
652
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
653
  if (ce)
 
654
    ret = ce->send_editor(SCI_GETLINECOUNT);
 
655
  return ret;
 
656
}
 
657
 
 
658
//------------------------------------------------------------------------------
 
659
void mforms::gtk::CodeEditorImpl::set_font(CodeEditor* self, const std::string &fontDescription)
 
660
{
 
661
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
662
  if (ce)
 
663
  {
 
664
    std::string name;
 
665
    int size = 10;
 
666
    bool bold = 0;
 
667
    bool italic = 0;
 
668
    if (base::parse_font_description(fontDescription, name, size, bold, italic))
 
669
    {
 
670
      if (!name.empty() && name[0] != '!')
 
671
        name = "!"+name;
 
672
      ce->send_editor(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)name.c_str());
 
673
      ce->send_editor(SCI_STYLESETSIZE, STYLE_DEFAULT, size);
 
674
      ce->send_editor(SCI_STYLESETBOLD, STYLE_DEFAULT, bold);
 
675
      ce->send_editor(SCI_STYLESETITALIC, STYLE_DEFAULT, italic);
 
676
    }
 
677
  }
 
678
}
 
679
 
 
680
//------------------------------------------------------------------------------
 
681
 
 
682
 
 
683
void mforms::gtk::CodeEditorImpl::notify(SCNotification *event)
 
684
{
 
685
  switch (event->nmhdr.code)
 
686
  {
 
687
    case SCN_MODIFIED:
 
688
      {
 
689
      const int mod_type = event->modificationType;
 
690
      if (mod_type & SC_MOD_INSERTTEXT || mod_type & SC_MOD_DELETETEXT)
 
691
      {
 
692
        //set_dirty(true);
 
693
        
 
694
        //_background_action_timer_conn.disconnect();
 
695
        //_background_action_timer_conn= Glib::signal_timeout().connect(
 
696
        //  sigc::mem_fun(this, &SqlEditorFE::on_background_action_timer),
 
697
        //  2000); //! get value from wb options
 
698
        _owner->text_changed(event->line, event->linesAdded);
 
699
      }
 
700
     // if (mod_type & SC_MOD_CHANGEFOLD)
 
701
     //   fold_changed(event->line, event->foldLevelNow, event->foldLevelPrev);
 
702
      }
 
703
      break;
 
704
 
 
705
    case SCN_MARGINCLICK:
 
706
      {
 
707
         int line = send_editor(SCI_LINEFROMPOSITION, event->position);
 
708
         if (event->margin == 2)
 
709
         {
 
710
           // Click on the folder margin. Toggle the current line if possible.
 
711
           send_editor(SCI_TOGGLEFOLD, line);
 
712
         }
 
713
        _owner->gutter_clicked(event->margin, line, (mforms::ModifierKey)event->modifiers);
 
714
      }
 
715
      break;
 
716
 
 
717
    case SCN_UPDATEUI:
 
718
      break;
 
719
  }
 
720
}
 
721
 
 
722
//------------------------------------------------------------------------------
 
723
void mforms::gtk::CodeEditorImpl::show_gutter(CodeEditor* self, bool on)
 
724
{
 
725
  CodeEditorImpl* ce = self->get_data<CodeEditorImpl>();
 
726
  if (ce)
 
727
  {
 
728
    if (on)
 
729
    {
 
730
      const int width = ce->send_editor(SCI_TEXTWIDTH, STYLE_LINENUMBER, (sptr_t)"_99999");
 
731
      ce->send_editor(SCI_SETMARGINWIDTHN, 0, width);
 
732
      ce->send_editor(SCI_SETMARGINSENSITIVEN, 0, true);
 
733
      ce->send_editor(SCI_SETMARGINWIDTHN, 1, 16);
 
734
      ce->send_editor(SCI_SETMARGINSENSITIVEN, 1, true);
 
735
      ce->send_editor(SCI_SETMARGINWIDTHN, 2, 16);
 
736
      ce->send_editor(SCI_SETMARGINSENSITIVEN, 2, true);
 
737
 
 
738
      //scintilla->Styles[Constants::STYLE_LINENUMBER]->ForeColor = Color::FromArgb(64, 64, 64);
 
739
      //scintilla->Styles[Constants::STYLE_LINENUMBER]->BackColor = Color::FromArgb(220, 220, 220);
 
740
      //scintilla->Margins->FoldMarginColor = Color::FromArgb(230, 230, 230);
 
741
 
 
742
    }
 
743
    else
 
744
    {
 
745
      ce->send_editor(SCI_SETMARGINWIDTHN, 0, 0);
 
746
      ce->send_editor(SCI_SETMARGINWIDTHN, 1, 0);
 
747
      ce->send_editor(SCI_SETMARGINWIDTHN, 2, 0);
 
748
    }
 
749
  }
 
750
}
 
751
 
 
752
 
 
753
//------------------------------------------------------------------------------
 
754
void mforms::gtk::CodeEditorImpl::init()
 
755
{
 
756
  ::mforms::ControlFactory *f = ::mforms::ControlFactory::get_instance();
 
757
 
 
758
  f->_code_editor_impl.create = mforms::gtk::CodeEditorImpl::create;
 
759
  f->_code_editor_impl.set_text = mforms::gtk::CodeEditorImpl::set_text;
 
760
  f->_code_editor_impl.get_text = mforms::gtk::CodeEditorImpl::get_text;
 
761
  f->_code_editor_impl.get_selection = mforms::gtk::CodeEditorImpl::get_selection;
 
762
  f->_code_editor_impl.set_selection = mforms::gtk::CodeEditorImpl::set_selection;
 
763
  f->_code_editor_impl.get_range_of_line = mforms::gtk::CodeEditorImpl::get_range_of_line;
 
764
  f->_code_editor_impl.set_language = mforms::gtk::CodeEditorImpl::set_language;
 
765
  f->_code_editor_impl.set_read_only = mforms::gtk::CodeEditorImpl::set_read_only;
 
766
  f->_code_editor_impl.show_markup = mforms::gtk::CodeEditorImpl::show_markup;
 
767
  f->_code_editor_impl.remove_markup = mforms::gtk::CodeEditorImpl::remove_markup;
 
768
  f->_code_editor_impl.line_count = mforms::gtk::CodeEditorImpl::line_count;
 
769
  f->_code_editor_impl.set_font = mforms::gtk::CodeEditorImpl::set_font;
 
770
  f->_code_editor_impl.show_gutter = mforms::gtk::CodeEditorImpl::show_gutter;
 
771
}