kolmck/Addons/ListEdit.pas

265 lines
6.2 KiB
ObjectPascal

unit ListEdit;
interface
uses KOL, Windows, Messages, objects;
const
WM_JUSTFREE = WM_USER + 51;
WM_EDITFREE = WM_USER + 52;
WM_DBLCLICK = WM_USER + 53;
WM_ROWCHANG = WM_USER + 54;
type
PListEdit =^TListEdit;
TKOLListEdit = PControl;
TListEdit = object(Tobj)
EList: PList;
Enter: boolean;
LView: PControl;
TabSave: boolean;
TabStrt: boolean;
OldWind: longint;
NewWind: longint;
CurEdit: integer;
destructor destroy; virtual;
procedure SetEvents(LV: PControl);
procedure NewWndProc(var Msg: TMessage);
procedure LVPaint;
procedure LVDblClk;
procedure LVChange(Store: boolean);
procedure PostFree(var Key: integer);
procedure EDChar(Sender: PControl; var Key: integer; Sh: Cardinal);
procedure EDPres(Sender: PControl; var Key: integer; Sh: Cardinal);
procedure EDentr(Sender: PObj);
end;
function NewListEdit(AParent: PControl; Style: TListViewStyle; Options: TListViewOptions;
ImageListSmall, ImageListNormal, ImageListState: PImageList): PControl;
implementation
function NewListEdit;
var p: PListEdit;
begin
Result := NewListView(AParent, Style, Options, ImageListSmall, ImageListNormal, ImageListState);
Result.CreateWindow;
New(p, create);
AParent.Add2AutoFree(p);
p.LView := Result;
p.SetEvents(PControl(Result));
end;
destructor TListEdit.destroy;
begin
LVChange(False);
EList.Free;
SetWindowLong(LView.Handle, GWL_WNDPROC, OldWind);
FreeObjectInstance(Pointer(NewWind));
inherited;
end;
procedure TListEdit.SetEvents;
begin
EList := NewList;
Enter := False;
TabStrt := False;
OldWind := GetWindowLong(LV.Handle, GWL_WNDPROC);
NewWind := LongInt(MakeObjectInstance(NewWndProc));
SetWindowLong(LV.Handle, GWL_WNDPROC, NewWind);
end;
procedure TListEdit.NewWndProc;
var e: boolean;
begin
e := EList.Count > 0;
case Msg.Msg of
WM_LBUTTONDOWN:
begin
LVChange(True);
CurEdit := 0;
if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0);
end;
WM_LBUTTONDBLCLK:
begin
LVDblClk;
end;
WM_KEYDOWN:
begin
if Msg.WParam = 13 then begin
LVDblClk;
end else
{ if Msg.WParam = 27 then begin
LVChange(False);
end else begin
LVChange(True);
if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0);
end;}
end;
WM_NCPAINT:
begin
LVPaint;
end;
WM_JUSTFREE:
begin
LVChange(Msg.WParam <> 27);
end;
WM_EDITFREE:
begin
LVChange(Msg.WParam <> 27);
if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0);
end;
WM_DBLCLICK:
begin
LVDblClk;
end;
WM_PAINT:
begin
LVPaint;
end;
end;
Msg.Result := CallWindowProc(Pointer(OldWind), LView.Handle, Msg.Msg, Msg.wParam, Msg.lParam);
end;
procedure TListEdit.LVPaint;
var i: integer;
r: TRect;
l: integer;
e: PControl;
p: TPoint;
begin
with LView^ do begin
SendMessage(Handle, WM_SETFONT, Font.Handle, 0);
l := 0;
p := LVItemPos[0];
for i := 0 to EList.Count - 1 do begin
r := LVItemRect(LVCurItem, lvipBounds);
r.Left := l + p.X;
r.Right := l + LVColWidth[i] + p.X;
Dec(r.Top);
Inc(r.Bottom);
e := EList.Items[i];
e.BoundsRect := r;
l := l + LVColWidth[i];
end;
end;
end;
procedure TListEdit.LVDblClk;
var i: integer;
e: PControl;
r: TRect;
l: integer;
a: PControl;
p: TPoint;
o: TPoint;
begin
with LView^ do begin
if EList.Count <> 0 then LVChange(True);
if enter then exit;
enter := true;
l := 0;
a := nil;
GetCursorPos(p);
p := Screen2Client(p);
o := LVItemPos[0];
for i := 0 to LVColCount - 1 do begin
r := LVItemRect(LVCurItem, lvipBounds);
r.Left := l + o.X;
r.Right := l + LVColWidth[i] + o.X;
l := l + LVColWidth[i];
Dec(r.Top);
Inc(r.Bottom);
e := NewEditBox(LView, []);
EList.Add(e);
e.BoundsRect := r;
e.DoubleBuffered := True;
e.Tabstop := True;
e.Font.FontHeight := LView.Font.FontHeight;
e.Font.FontCharset := 204;
e.Text := LVItems[LVCurItem, i];
e.OnKeyDown := EDChar;
e.OnKeyUp := EDPres;
e.OnEnter := EDEntr;
e.Show;
if a = nil then a := e;
if (CurEdit <> 0) then
if (EList.Count = CurEdit) then a := e else else
if (r.Left <= p.x) and (r.Right >= p.x) then
a := e;
end;
if a <> nil then a.Focused := True;
TabSave := TabStop;
TabStop := False;
TabStrt := True;
enter := false;
end;
end;
procedure TListEdit.LVChange;
var e: PControl;
i: integer;
g: boolean;
begin
with LView^ do begin
if enter then exit;
enter := true;
g := False;
for i := 0 to EList.Count - 1 do begin
e := EList.Items[i];
if Store then begin
g := g or (LVItems[LVCurItem, i] <> e.Text);
LVItems[LVCurItem, i] := e.Text;
end;
if e.Focused then CurEdit := i + 1;
e.Free;
end;
EList.Clear;
enter := false;
if TabStrt then TabStop := TabSave;
if g then
SendMessage(Parent.Handle, WM_ROWCHANG, LVCurItem, 0);
end;
end;
procedure TListEdit.PostFree;
begin
with LView^ do begin
if Key = 27 then
PostMessage(Handle, WM_JUSTFREE, key, 0);
if Key = 13 then
PostMessage(Handle, WM_EDITFREE, key, 0);
if ((key = 40) and (LView.LVCurItem < LView.LVCount - 1)) or
((key = 38) and (LView.LVCurItem > 0)) then begin
PostMessage(Handle, WM_EDITFREE, key, 0);
PostMessage(Handle, wm_keydown, Key, 0);
PostMessage(Handle, wm_keyup, Key, 0);
end;
end;
end;
procedure TListEdit.EDChar;
begin
case key of
13,
27,
38,
40: PostFree(key);
end;
end;
procedure TListEdit.EDPres;
begin
case key of
38,
40: key := 0;
end;
end;
procedure TListEdit.EDentr;
begin
PControl(Sender).SelectAll;
end;
end.