View previous topic :: View next topic |
Author |
Message |
Andrej08
Joined: 31 Aug 2010 Posts: 51
|
Posted: Thu Sep 09, 2010 2:20 pm Post subject: Updated ScintillaControl for D2 |
|
|
Hi,
I've updated the DFL ScintillaControl addin. All it took was a few changes from char[] to string, and inout to ref.
You can download it here: Link
The only changed file is import\dfl\scintilla.dll. Of course, you will have to change the import library batch file because it still references old DMD1 paths.
When you use the Scintilla control, it's best to explicitly set the .dll name to load when calling the constructor, for example in the sample code from ScintillaControl, there's this in dflscitest.d:
Code: |
this()
{
//with(sci = new Scintilla("dlex.dll"))
with(sci = new Scintilla)
{
...
}
}
|
It's best to call the constructor with an argument Scintilla("file.dll"), otherwise Windows will try to load the SciLexer.dll from another place if it's not in the current directory. I had the situation where it was loading the SciLexer.dll from a completely different place because it happened to be in my PATH variable.
Cheers. |
|
Back to top |
|
|
Andrej08
Joined: 31 Aug 2010 Posts: 51
|
Posted: Thu Sep 09, 2010 7:05 pm Post subject: |
|
|
One question, is it unecessary to use dlex anymore? The latest versions of Scintilla seem to support the D language.
I'll have to build the new Scintilla .dll and update the header files, there's plenty of new opcodes to play with. |
|
Back to top |
|
|
Andrej08
Joined: 31 Aug 2010 Posts: 51
|
Posted: Thu Sep 09, 2010 8:15 pm Post subject: |
|
|
Well, that was easy. I copied SciLexer.h & Scintilla.h from the Scintilla v2.21 codebase, used htod to translate to D, and rebuilt the import lib. It seems to work on first try, but I have to test the messages. htod was kind enough to translate all typedefs, pretty awesome (yay for -ht flag). |
|
Back to top |
|
|
Andrej08
Joined: 31 Aug 2010 Posts: 51
|
Posted: Fri Oct 15, 2010 1:29 pm Post subject: |
|
|
Just a small update:
To get messages from the Scintilla component, add the onReflectedMessage method to the Scintilla class, and override it in any subclasses that you create so you can catch and handle the messages. Add this to the Scintilla class:
Code: | // This method is required for getting messages from
// Scintilla. We catch WM_NOTIFY message types,
// and call the super method to handle the rest.
protected override void onReflectedMessage(ref Message m)
{
super.onReflectedMessage(m);
} |
Also, in the method "protected override void wndProc(ref Message m)" there's a case "EM_SETSEL:". You can comment that section out for the case, because it keeps selecting the entire contents of the window whenever a dialog is closed. Otherwise you can do your own handling in the Scintilla class or one that overrides it.
FYI it's very easy to use Scintilla via D, I've ported some Scite autoindentation functionality to D with ease. Have fun! |
|
Back to top |
|
|
Andrej08
Joined: 31 Aug 2010 Posts: 51
|
Posted: Fri Oct 15, 2010 1:38 pm Post subject: |
|
|
Oh I forgot to mention how to handle the messages. There are 2 types of messages scintilla sends, wmnotify and wmcommand, see the scintilla docs for explanation. Here's a simple implementation that opens/saves files and uses D syntax highlighting, and maintains indentation just like Scite:
Code: |
import dfl.all;
import dfl.scintilla; // DFL control.
import dfl.cpp.scintilla, dfl.cpp.scilexer; // For scintilla/scite constants.
import std.c.windows.windows;
import std.stdio;
import std.exception;
import std.regex;
import std.algorithm;
import std.getopt;
import std.string;
import std.conv : to;
import std.path;
string dKeywords = "property abstract alias align asm assert auto body bool break byte case cast catch cdouble cent cfloat char class const continue creal dchar dstring debug default delegate delete deprecated do double else enum export extern false final finally float for foreach foreach_reverse function goto idouble if ifloat immutable import in inout int interface invariant ireal is lazy long macro mixin module new nothrow null out override package pragma private protected public pure real ref return scope shared short size_t static string struct super switch synchronized template this throw true try typedef typeid typeof ubyte ucent uint ulong union unittest ushort version void volatile wchar wstring while with __FILE__ __LINE__ __gshared __thread __traits const_cast dynamic_cast explicit friend inline mutable namespace operator register reinterpret_cast restrict signed sizeof static_cast typename unsigned using virtual int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t int_least8_t uint_least8_t int_least16_t uint_least16_t int_least32_t uint_least32_t int_least64_t uint_least64_t int_fast8_t uint_fast8_t int_fast16_t uint_fast16_t int_fast32_t uint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t intmax_t uintmax_t wint_t wchar_t wctrans_t wctype_t time_t and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq complex imaginary _Complex _Imaginary _Bool _Pragma";
struct NMHDR
{
HWND hwndFrom;
UINT idFrom;
UINT code;
}
alias NMHDR* LPNMHDR;
class ScintillaExt : Scintilla
{
struct CRange
{
int min;
int max;
}
this(string dllname = null)
{
super(dllname);
}
protected override void onReflectedMessage(ref Message m)
{
switch(m.msg)
{
case WM_NOTIFY:
notify(cast(SCNotification*)m.lParam);
break;
case WM_COMMAND:
///~ writeln("context switch");
return;
default: ;
}
super.onReflectedMessage(m);
}
void notify(SCNotification *notification)
{
switch (notification.nmhdr.code)
{
case SCN_CHARADDED:
maintainIndentation(cast(char)notification.ch);
break;
case SCN_DOUBLECLICK:
///~ writeln("double clicked");
break;
default: ;
}
}
int GetCurrentLineNumber()
{
auto temp = sendEditor(SCI_GETCURRENTPOS, 0);
return sendEditor(SCI_LINEFROMPOSITION, temp);
}
int GetLineLength(int line)
{
return sendEditor(SCI_GETLINEENDPOSITION, line) - sendEditor(SCI_POSITIONFROMLINE, line);
}
int GetLineIndentation(int line)
{
return sendEditor(SCI_GETLINEINDENTATION, line);
}
auto GetSelection()
{
auto min = sendEditor(SCI_GETSELECTIONSTART);
auto max = sendEditor(SCI_GETSELECTIONEND);
///~ return { int min = xmin; int max = xmax; };
return CRange(min, max);
}
int GetLineIndentPosition(int line)
{
return sendEditor(SCI_GETLINEINDENTPOSITION, line);
}
void SetSelection(int anchor, int currentPos)
{
sendEditor(SCI_SETSEL, anchor, currentPos);
}
void SetLineIndentation(int line, int indent)
{
if (indent < 0)
{
return;
}
auto crange = GetSelection();
int posBefore = GetLineIndentPosition(line);
sendEditor(SCI_SETLINEINDENTATION, line, indent);
int posAfter = GetLineIndentPosition(line);
int posDifference = posAfter - posBefore;
if (posAfter > posBefore)
{
// Move selection on
if (crange.min >= posBefore)
{
crange.min += posDifference;
}
if (crange.max >= posBefore)
{
crange.max += posDifference;
}
}
else if (posAfter < posBefore)
{
// Move selection back
if (crange.min >= posAfter)
{
if (crange.min >= posBefore)
{
crange.min += posDifference;
}
else
{
crange.min = posAfter;
}
}
if (crange.max >= posAfter)
{
if (crange.max >= posBefore)
{
crange.max += posDifference;
}
else
{
crange.max = posAfter;
}
}
}
SetSelection(crange.min, crange.max);
}
void maintainIndentation(char ch)
{
int eolMode = sendEditor(SCI_GETEOLMODE, 0);
int curLine = GetCurrentLineNumber();
int lastLine = curLine - 1;
if (((eolMode == SC_EOL_CRLF || eolMode == SC_EOL_LF) && ch == '\n') ||
(eolMode == SC_EOL_CR && ch == '\r'))
{
while (lastLine >= 0 && GetLineLength(lastLine) == 0)
lastLine--;
int indentAmount = 0;
if (lastLine >= 0)
{
indentAmount = GetLineIndentation(lastLine);
}
if (indentAmount > 0)
{
SetLineIndentation(curLine, indentAmount);
}
}
}
string getLine(int line)
{
uint len;
char[] result;
len = sendEditor(SCI_LINELENGTH, line);
if(!len)
return null;
result = new char[len + 1];
sendEditor(SCI_GETLINE, line, cast(LPARAM)result.ptr);
return result[0 .. len].idup;
}
}
class SciTestForm : dfl.form.Form
{
ScintillaExt sci;
string currentFile;
string currentPath;
this()
{
//~ Add shortcut keys
addShortcut(Keys.ESCAPE, &close_app);
addShortcut(Keys.CONTROL | Keys.O, &open_file);
addShortcut(Keys.CONTROL | Keys.N, &new_file);
addShortcut(Keys.CONTROL | Keys.S, &save_file);
addShortcut(Keys.F4, &build_handler);
startPosition = FormStartPosition.MANUAL;
size = Size(700, 500);
setDesktopLocation(100, 50);
text = "Scintilla Test Form";
// No borders
//~ formBorderStyle(FormBorderStyle.NONE);
// Center
//~ centerToScreen();
// works
//~ clientSize = dfl.all.Size(400, 400);
//~ setDesktopLocation(1600, 0);
//~ desktopLocation(Point(500, 0));
//~ writeln(desktopLocation().x);
// ?
//~ setDesktopBounds(100, 100, 200, 200);
//~ maximumSize = Size(400, 400);
//~ setClientSizeCore(200, 200);
//~ Load the dll and create a new scintilla object
with(sci = new typeof(sci)("SciLexer.dll"))
{
// some initial text
text = "#! --unittest --c --release\n\nimport std.stdio, std.regex;\n\nimport std.c.windows.windows : GetAddress;\n\nimport third.module;\n\n\nint foo = 42;";
dock = DockStyle.FILL;
parent = this;
handleCreated ~= &sci_handleCreated;
}
}
private:
private void close_app(Object sender, FormShortcutEventArgs ea)
{
Application.exitThread();
}
void sci_handleCreated(Object sender, EventArgs ea)
{
with(sci)
{
// Set the lexer. CPP one is for C/C++/D/etc.
///~ sendEditor(SCI_SETLEXER, SCLEX_CPP);
sendEditor(SCI_SETLEXER, SCLEX_D);
// Default font name.
sendEditor(SCI_STYLESETFONT, STYLE_DEFAULT, "Courier New");
// Default font size.
sendEditor(SCI_STYLESETSIZE, STYLE_DEFAULT, 10);
// Set keywords.
//~ sendEditor(SCI_SETKEYWORDS, 0, "byte ubyte short ushort int uint long ulong");
sendEditor(SCI_SETKEYWORDS, 0, dKeywords);
// Color of keywords.
///~ sendEditor(SCI_STYLESETFORE, SCE_C_WORD, Color(0, 0, 0xFF).toRgb());
sendEditor(SCI_STYLESETFORE, SCE_D_WORD, Color(0, 0, 0xFF).toRgb());
// tabs
sendEditor(SCI_SETTABINDENTS, true);
sendEditor(SCI_SETBACKSPACEUNINDENTS, true);
sendEditor(SCI_SETUSETABS, false);
sendEditor(SCI_SETTABWIDTH, 4);
// eol - unix (lf)
sendEditor(SCI_SETEOLMODE, SC_EOL_LF);
///~ sendEditor(SCI_SETVIEWEOL, true);
///~ Use for conversion: SCI_CONVERTEOLS(int eolMode)
// white space
///~ sendEditor(SCI_SETVIEWWS, SCWS_VISIBLEAFTERINDENT);
///~ sendEditor(SCI_SETVIEWWS, SCWS_VISIBLEALWAYS);
// caret blink off
sendEditor(SCI_SETCARETPERIOD, 0);
// wrapping
sendEditor(SCI_SETWRAPMODE, SC_WRAP_WORD);
///~ sendEditor(SCI_SETWRAPINDENTMODE, SC_WRAPINDENT_INDENT);
sendEditor(SCI_SETWRAPINDENTMODE, SC_WRAPINDENT_SAME);
// horizontal scrollbar
sendEditor(SCI_SETHSCROLLBAR, 0);
// lexer properties
///~ setProperty("style.d.1", "fore:#0000CC");
///~ writeln(getProperty("style.d.1"));
///~ sendEditor(SCI_SETWHITESPACESIZE, 5);
///~ writeln(sendEditor(SCI_GETWHITESPACESIZE, 0));
}
}
void open_file(Object sender, FormShortcutEventArgs ea)
{
with(sci)
{
auto openFile = new OpenFileDialog;
openFile.showDialog;
if (!openFile.fileName)
{
return;
}
File file = File(openFile.fileName, "r");
sendEditor(SCI_CLEARALL);
// buffered read
foreach (ubyte[] buffer; file.byChunk(4096))
{
sendEditor(SCI_ADDTEXT, buffer.length, cast(LPARAM)buffer.ptr);
}
file.close();
this.currentFile = openFile.fileName;
this.currentPath = dirname(openFile.fileName) ~ r"\";
///~ Convert to unix newlines
sci.sendEditor(SCI_CONVERTEOLS, SC_EOL_LF);
}
}
void new_file(Object sender, FormShortcutEventArgs ea)
{
sci.sendEditor(SCI_CLEARALL);
}
void save_file(Object sender, FormShortcutEventArgs ea)
{
with(sci)
{
auto saveFile = new SaveFileDialog;
saveFile.showDialog;
if (!saveFile.fileName)
{
return;
}
File file = File(saveFile.fileName, "w");
auto buffer = text();
file.write(buffer);
}
}
}
int main()
{
int result = 0;
try
{
Application.run(new SciTestForm());
}
catch(Object o)
{
msgBox(o.toString(), "crash", MsgBoxButtons.OK, MsgBoxIcon.ERROR);
result = 1;
}
return result;
}
|
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|