{****************************************************************** JEDI-VCL Demo Copyright (C) 2002 Project JEDI Original author: Contributor(s): You may retrieve the latest version of this file at the JEDI-JVCL home page, located at http://jvcl.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1_1Final.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. ******************************************************************} unit EditorMainFormU; interface uses Windows, Messages, Forms, StdCtrls, Dialogs, Mask, ImgList, Controls, Menus, JvMenus, ComCtrls, ExtCtrls, Classes, ActiveX, JvComponent, JvAppEvent, JvMaskEdit, JvSpin, JvCombobox, JvColorCombo, JvSpeedBar, JvRichEdit, JvClipboardMonitor, JvExMask, JvExStdCtrls, JvExExtCtrls, XPColorMenuItemPainter; type TEditorMainForm = class(TForm) MainMenu: TJvMainMenu; FileNewItem: TMenuItem; FileOpenItem: TMenuItem; FileSaveItem: TMenuItem; FileSaveAsItem: TMenuItem; FilePrintItem: TMenuItem; FileExitItem: TMenuItem; EditUndoItem: TMenuItem; EditCutItem: TMenuItem; EditCopyItem: TMenuItem; EditPasteItem: TMenuItem; HelpAboutItem: TMenuItem; OpenDialog: TOpenDialog; SaveDialog: TSaveDialog; PrintDialog: TPrintDialog; Ruler: TPanel; FontDialog: TFontDialog; FirstInd: TLabel; LeftInd: TLabel; RulerLine: TBevel; RightInd: TLabel; Editor: TJvRichEdit; StatusBar: TStatusBar; ToolbarImages: TImageList; InsertMenu: TMenuItem; InsertImageItem: TMenuItem; InsertObjectItem: TMenuItem; EditRedoItem: TMenuItem; FormatMenu: TMenuItem; FormatFontItem: TMenuItem; FormatParagraphItem: TMenuItem; N3: TMenuItem; EditFindItem: TMenuItem; EditReplaceItem: TMenuItem; ColorMenu: TJvPopupMenu; EditPasteSpecial: TMenuItem; SpeedBar: TJvSpeedBar; FormatBar: TJvSpeedBar; SpeedbarSection1: TJvSpeedBarSection; SpeedbarSection2: TJvSpeedBarSection; NewBtn: TJvSpeedItem; OpenBtn: TJvSpeedItem; SaveBtn: TJvSpeedItem; PrintBtn: TJvSpeedItem; CutBtn: TJvSpeedItem; CopyBtn: TJvSpeedItem; PasteBtn: TJvSpeedItem; UndoBtn: TJvSpeedItem; RedoBtn: TJvSpeedItem; FindBtn: TJvSpeedItem; FontName: TJvFontComboBox; FontSize: TJvSpinEdit; SpeedbarSection3: TJvSpeedBarSection; BoldBtn: TJvSpeedItem; ItalicBtn: TJvSpeedItem; UnderlineBtn: TJvSpeedItem; ColorBtn: TJvSpeedItem; LeftBtn: TJvSpeedItem; CenterBtn: TJvSpeedItem; RightBtn: TJvSpeedItem; SubscriptBtn: TJvSpeedItem; SuperscriptBtn: TJvSpeedItem; BulletsBtn: TJvSpeedItem; N5: TMenuItem; EditObjPropsItem: TMenuItem; EditPopupMenu: TJvPopupMenu; CutItm: TMenuItem; CopyItm: TMenuItem; PasteItm: TMenuItem; BackgroundBtn: TJvSpeedItem; BackgroundMenu: TJvPopupMenu; N6: TMenuItem; ProtectedItem: TMenuItem; DisabledItem: TMenuItem; HiddenItem: TMenuItem; EditFindNextItem: TMenuItem; EditSelectAllItem: TMenuItem; FileSaveSelItem: TMenuItem; App: TJvAppEvents; FormatTabsItem: TMenuItem; JustifyBtn: TJvSpeedItem; procedure SelectionChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ShowHint(Sender: TObject); procedure FileNew(Sender: TObject); procedure FileOpen(Sender: TObject); procedure FileSave(Sender: TObject); procedure FileSaveAs(Sender: TObject); procedure FilePrint(Sender: TObject); procedure FileExit(Sender: TObject); procedure EditUndo(Sender: TObject); procedure EditCut(Sender: TObject); procedure EditCopy(Sender: TObject); procedure EditPaste(Sender: TObject); procedure HelpAbout(Sender: TObject); procedure SelectFont(Sender: TObject); procedure RulerResize(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormPaint(Sender: TObject); procedure BoldButtonClick(Sender: TObject); procedure ItalicButtonClick(Sender: TObject); procedure FontSizeChange(Sender: TObject); procedure AlignButtonClick(Sender: TObject); procedure FontNameChange(Sender: TObject); procedure UnderlineButtonClick(Sender: TObject); procedure BulletsButtonClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure RulerItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure RulerItemMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure FirstIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure LeftIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure RightIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormShow(Sender: TObject); procedure RichEditChange(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure InsertObject(Sender: TObject); procedure EditRedo(Sender: TObject); procedure InsertBitmap(Sender: TObject); procedure FormatParaAttributes(Sender: TObject); procedure EditorURLClick(Sender: TObject; const URLText: string; Button: TMouseButton); procedure FormActivate(Sender: TObject); procedure EditFindClick(Sender: TObject); procedure EditReplaceClick(Sender: TObject); procedure MainMenuGetImageIndex(Sender: TMenu; Item: TMenuItem; State: TMenuOwnerDrawState; var ImageIndex: Integer); procedure ColorMenuPopup(Sender: TObject); procedure SubscriptClick(Sender: TObject); procedure EditPasteSpecialClick(Sender: TObject); procedure EditObjPropsItemClick(Sender: TObject); procedure EditPopupMenuGetImageIndex(Sender: TMenu; Item: TMenuItem; State: TMenuOwnerDrawState; var ImageIndex: Integer); procedure BackgroundMenuPopup(Sender: TObject); procedure ProtectedItemClick(Sender: TObject); procedure DisabledItemClick(Sender: TObject); procedure EditorProtectChange(Sender: TObject; StartPos, EndPos: Integer; var AllowChange: Boolean); procedure HiddenItemClick(Sender: TObject); procedure EditFindNextItemClick(Sender: TObject); procedure EditorTextNotFound(Sender: TObject; const FindText: string); procedure EditSelectAll(Sender: TObject); procedure FileSaveSelected(Sender: TObject); procedure FormatParaTabs(Sender: TObject); procedure EditorQueryAcceptData(Sender: TObject; const ADataObject: IDataObject; var AFormat: Word; ClipboardOperationKind: Cardinal; Really: Boolean; IconMetaPict: Cardinal; var Handled: Boolean); procedure EditorGetDragDropEffect(Sender: TObject; ShiftState: TShiftState; var AllowedEffects: TRichDropEffects; var Handled: Boolean); private FFileName: string; FUpdating: Boolean; FDragOfs: Integer; FLineOfs: Integer; FLineDC: HDC; FLinePen: HPen; FLineVisible: Boolean; FDragging: Boolean; FProtectChanging: Boolean; FClipboardMonitor: TJvClipboardMonitor; FOpenPictureDialog: TOpenDialog; FDragStartedHere: Boolean; function IndentToRuler(Indent: Integer; IsRight: Boolean): Integer; function RulerToIndent(RulerPos: Integer; IsRight: Boolean): Integer; procedure DrawLine; procedure CalcLineOffset(Control: TControl); function CurrText: TJvTextAttributes; procedure SetFileName(const FileName: string); procedure EditFindDialogClose(Sender: TObject; Dialog: TFindDialog); procedure ColorItemClick(Sender: TObject); procedure BackgroundItemClick(Sender: TObject); procedure CheckFileSave; procedure SetupRuler; procedure SetEditRect; procedure UpdateCursorPos; procedure FocusEditor; procedure ClipboardChanged(Sender: TObject); procedure PerformFileOpen(const AFileName: string); procedure SetModified(Value: Boolean); procedure DropFiles(DropHandle: Integer); end; var EditorMainForm: TEditorMainForm; implementation uses Graphics, SysUtils, Math, ShellAPI, ClipBrd, ExtDlgs, Jpeg, RichEdit, JvGIF, JvWinDialogs, JvJVCLUtils, ParagraphFormatFormU, TabsFormU; {$R *.DFM} const RulerAdj = 4 / 3; GutterWid: Integer = 6; UndoNames: array[TUndoName] of string = ('', 'typing', 'delete', 'drag and drop', 'cut', 'paste'); ColorValues: array[0..16] of TColor = ( clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite, clWindowText); BackValues: array[0..16] of TColor = ( clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite, clWindow); function ColorName(Color: TColor): string; begin if (Color = clWindowText) or (Color = clWindow) or (Color = clDefault) then Result := 'Automatic' else begin Result := ColorToString(Color); if Pos('cl', Result) = 1 then Delete(Result, 1, 2); end; end; //=== TEditorMainForm ======================================================== procedure TEditorMainForm.AlignButtonClick(Sender: TObject); begin if FUpdating then Exit; Editor.Paragraph.Alignment := TParaAlignment(TComponent(Sender).Tag); end; procedure TEditorMainForm.BackgroundItemClick(Sender: TObject); begin with Sender as TMenuItem do begin Checked := True; CurrText.BackColor := Tag; end; end; procedure TEditorMainForm.BackgroundMenuPopup(Sender: TObject); var I: Integer; C: TColor; begin C := CurrText.BackColor; for I := 0 to 16 do BackgroundMenu.Items[I].Checked := (C = BackValues[I]); end; procedure TEditorMainForm.BoldButtonClick(Sender: TObject); begin if FUpdating then Exit; if BoldBtn.Down then CurrText.Style := CurrText.Style + [fsBold] else CurrText.Style := CurrText.Style - [fsBold]; end; procedure TEditorMainForm.BulletsButtonClick(Sender: TObject); begin if FUpdating then Exit; Editor.Paragraph.Numbering := TJvNumbering(BulletsBtn.Down); end; procedure TEditorMainForm.CalcLineOffset(Control: TControl); var P: TPoint; begin with Control do P := ClientToScreen(Point(0, 0)); P := Editor.ScreenToClient(P); FLineOfs := P.X + FDragOfs; end; procedure TEditorMainForm.CheckFileSave; var SaveResp: Integer; begin if not Editor.Modified then Exit; SaveResp := MessageDlg(Format('Save changes to %s?', [FFileName]), mtConfirmation, mbYesNoCancel, 0); try case SaveResp of mrYes: FileSave(Self); mrNo: {Nothing}; mrCancel: Abort; end; finally FocusEditor; end; end; procedure TEditorMainForm.ClipboardChanged(Sender: TObject); var E: Boolean; begin { check to see if we can paste what's on the clipboard } E := Editor.CanPaste; PasteBtn.Enabled := E; EditPasteItem.Enabled := E; EditPasteSpecial.Enabled := E; PasteItm.Enabled := E; end; procedure TEditorMainForm.ColorItemClick(Sender: TObject); begin with Sender as TMenuItem do begin Checked := True; CurrText.Color := Tag; end; end; procedure TEditorMainForm.ColorMenuPopup(Sender: TObject); var I: Integer; C: TColor; begin C := CurrText.Color; for I := 0 to 16 do ColorMenu.Items[I].Checked := (C = ColorValues[I]); end; function TEditorMainForm.CurrText: TJvTextAttributes; begin if Editor.SelLength > 0 then Result := Editor.SelAttributes else Result := Editor.WordAttributes; end; procedure TEditorMainForm.DisabledItemClick(Sender: TObject); begin if FUpdating then Exit; CurrText.Disabled := not CurrText.Disabled; DisabledItem.Checked := CurrText.Disabled; end; procedure TEditorMainForm.DrawLine; var P: TPoint; begin FLineVisible := not FLineVisible; P := Point(0, 0); Inc(P.X, FLineOfs); with P, Editor do begin MoveToEx(FLineDC, X, Y, nil); LineTo(FLineDC, X, Y + ClientHeight); end; end; procedure TEditorMainForm.EditCopy(Sender: TObject); begin Editor.CopyToClipboard; end; procedure TEditorMainForm.EditCut(Sender: TObject); begin Editor.CutToClipboard; end; procedure TEditorMainForm.EditFindClick(Sender: TObject); begin with Editor do FindDialog(SelText); end; procedure TEditorMainForm.EditFindDialogClose(Sender: TObject; Dialog: TFindDialog); begin FocusEditor; end; procedure TEditorMainForm.EditFindNextItemClick(Sender: TObject); begin if not Editor.FindNext then Beep; FocusEditor; end; procedure TEditorMainForm.EditObjPropsItemClick(Sender: TObject); begin Editor.ObjectPropertiesDialog; end; procedure TEditorMainForm.EditorProtectChange(Sender: TObject; StartPos, EndPos: Integer; var AllowChange: Boolean); begin AllowChange := FProtectChanging; end; procedure TEditorMainForm.EditorTextNotFound(Sender: TObject; const FindText: string); begin MessageDlg(Format('Text "%s" not found.', [FindText]), mtWarning, [mbOK], 0); end; procedure TEditorMainForm.EditorURLClick(Sender: TObject; const URLText: string; Button: TMouseButton); begin if Button = mbLeft then ShellExecute(Handle, nil, PChar(URLText), nil, nil, SW_SHOW); end; procedure TEditorMainForm.EditPaste(Sender: TObject); begin Editor.PasteFromClipboard; end; procedure TEditorMainForm.EditPasteSpecialClick(Sender: TObject); begin try Editor.PasteSpecialDialog; finally FocusEditor; end; end; procedure TEditorMainForm.EditPopupMenuGetImageIndex(Sender: TMenu; Item: TMenuItem; State: TMenuOwnerDrawState; var ImageIndex: Integer); begin if (Item = CutItm) or (Item = CopyItm) or (Item = PasteItm) then ImageIndex := Item.Tag; end; procedure TEditorMainForm.EditRedo(Sender: TObject); begin Editor.Redo; RichEditChange(nil); SelectionChange(nil); end; procedure TEditorMainForm.EditReplaceClick(Sender: TObject); begin with Editor do ReplaceDialog(SelText, ''); end; procedure TEditorMainForm.EditSelectAll(Sender: TObject); begin Editor.SelectAll; end; procedure TEditorMainForm.EditUndo(Sender: TObject); begin Editor.Undo; RichEditChange(nil); SelectionChange(nil); end; procedure TEditorMainForm.FileExit(Sender: TObject); begin Close; end; procedure TEditorMainForm.FileNew(Sender: TObject); begin CheckFileSave; SetFileName('Untitled'); FProtectChanging := True; try Editor.Lines.Clear; Editor.Modified := False; Editor.ReadOnly := False; SetModified(False); with Editor do begin DefAttributes.Assign(Font); SelAttributes.Assign(Font); end; SelectionChange(nil); finally FProtectChanging := False; end; end; procedure TEditorMainForm.FileOpen(Sender: TObject); begin CheckFileSave; if OpenDialog.Execute then begin Editor.Refresh; PerformFileOpen(OpenDialog.FileName); Editor.ReadOnly := ofReadOnly in OpenDialog.Options; end; end; procedure TEditorMainForm.FilePrint(Sender: TObject); begin if PrintDialog.Execute then Editor.Print(FFileName); end; procedure TEditorMainForm.FileSave(Sender: TObject); begin if FFileName = 'Untitled' then FileSaveAs(Sender) else begin Editor.Lines.SaveToFile(FFileName); Editor.Modified := False; SetModified(False); RichEditChange(nil); end; end; procedure TEditorMainForm.FileSaveAs(Sender: TObject); begin if SaveDialog.Execute then begin Editor.Lines.SaveToFile(SaveDialog.FileName); SetFileName(SaveDialog.FileName); Editor.Modified := False; SetModified(False); RichEditChange(nil); end; FocusEditor; end; procedure TEditorMainForm.FileSaveSelected(Sender: TObject); begin if SaveDialog.Execute then begin with Editor do try StreamMode := [smSelection]; Lines.SaveToFile(SaveDialog.FileName); finally StreamMode := []; end; RichEditChange(nil); end; FocusEditor; end; procedure TEditorMainForm.FirstIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FDragging := False; Editor.Paragraph.FirstIndent := Max(0, RulerToIndent(FirstInd.Left + FDragOfs, False)); LeftIndMouseUp(Sender, Button, Shift, X, Y); end; procedure TEditorMainForm.FocusEditor; begin with Editor do if CanFocus then SetFocus; end; procedure TEditorMainForm.FontNameChange(Sender: TObject); begin if FUpdating then Exit; CurrText.Name := FontName.FontName; end; procedure TEditorMainForm.FontSizeChange(Sender: TObject); begin if FUpdating then Exit; if FontSize.AsInteger > 0 then CurrText.Size := FontSize.AsInteger; end; procedure TEditorMainForm.FormActivate(Sender: TObject); begin FocusEditor; end; procedure TEditorMainForm.FormatParaAttributes(Sender: TObject); begin FormatParagraph(Editor.Paragraph); FocusEditor; end; procedure TEditorMainForm.FormatParaTabs(Sender: TObject); begin FormatTabs(Editor.Paragraph); FocusEditor; end; procedure TEditorMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin try CheckFileSave; except CanClose := False; end; end; procedure TEditorMainForm.FormCreate(Sender: TObject); var I: Integer; Item: TMenuItem; const SPictureFilter = '%s|%s|%s|%s'; begin // The TComponent destructor should handle the destruction of the // painters because we indicate the form (self) as the owner of // the objects. But we are extra careful and destroy them ourselves // in FormDestroy anyway. ColorMenu.ItemPainter := TJvXPColorMenuItemPainter.Create(Self); BackgroundMenu.ItemPainter := TJvXPColorMenuItemPainter.Create(Self); Editor.RegisterMSTextConverters; OpenDialog.InitialDir := ExtractFilePath(ParamStr(0)); OpenDialog.Filter := Editor.Filter(ckImport); SaveDialog.InitialDir := OpenDialog.InitialDir; SaveDialog.Filter := Editor.Filter(ckExport); SetFileName('Untitled'); SetupRuler; HandleNeeded; SelectionChange(Self); Editor.OnCloseFindDialog := EditFindDialogClose; FOpenPictureDialog := TOpenPictureDialog.Create(Self); with FOpenPictureDialog do Filter := Format(SPictureFilter, [ GraphicFilter(TBitmap), GraphicFilter(TMetafile), GraphicFilter(TJPEGImage), GraphicFilter(TJvGIFImage) ]); with ColorMenu.Items do begin while Count > 0 do Items[Count - 1].Free; for I := 0 to 16 do begin Item := NewItem(ColorName(ColorValues[I]), scNone, False, True, ColorItemClick, 0, ''); Item.RadioItem := True; Item.Tag := ColorValues[I]; Add(Item); end; end; with BackgroundMenu.Items do begin while Count > 0 do Items[Count - 1].Free; for I := 0 to 16 do begin Item := NewItem(ColorName(BackValues[I]), scNone, False, True, BackgroundItemClick, 0, ''); Item.RadioItem := True; Item.Tag := BackValues[I]; Add(Item); end; end; FClipboardMonitor := TJvClipboardMonitor.Create(Self); FClipboardMonitor.OnChange := ClipboardChanged; SuperscriptBtn.Enabled := RichEditVersion >= 2; SubscriptBtn.Enabled := RichEditVersion >= 2; BackgroundBtn.Enabled := RichEditVersion >= 2; DisabledItem.Enabled := RichEditVersion >= 2; HiddenItem.Enabled := RichEditVersion >= 2; JustifyBtn.Enabled := RichEditVersion >= 3; end; procedure TEditorMainForm.FormDestroy(Sender: TObject); begin ColorMenu.ItemPainter.Free; ColorMenu.ItemPainter := nil; BackgroundMenu.ItemPainter.Free; BackgroundMenu.ItemPainter := nil; { remove ourselves from the viewer chain } FClipboardMonitor.Free; end; procedure TEditorMainForm.FormPaint(Sender: TObject); begin SetEditRect; end; procedure TEditorMainForm.FormResize(Sender: TObject); begin SetEditRect; SelectionChange(Sender); end; procedure TEditorMainForm.FormShow(Sender: TObject); var Res: TResourceStream; begin UpdateCursorPos; RichEditChange(nil); FocusEditor; ClipboardChanged(nil); { check if we should load a file from the command line } if (ParamCount > 0) and FileExists(ParamStr(1)) then PerformFileOpen(ParamStr(1)) else begin StartWait; try Res := TResourceStream.Create(HInstance, 'OVERVIEWRTF', 'RTF'); try Editor.Lines.LoadFromStream(Res); SetFileName('Untitled'); Editor.Modified := False; SetModified(False); finally Res.Free; end; except { ignore exceptions } end; StopWait; end; end; procedure TEditorMainForm.HelpAbout(Sender: TObject); begin with TJvShellAboutDialog.Create(Application) do try Caption := 'RichEdit 2.0 Control Demo'; OtherText := 'RX Library Demo Program'; Execute; finally Free; end; FocusEditor; end; procedure TEditorMainForm.HiddenItemClick(Sender: TObject); begin if FUpdating then Exit; CurrText.Hidden := not CurrText.Hidden; HiddenItem.Checked := CurrText.Hidden; end; function TEditorMainForm.IndentToRuler(Indent: Integer; IsRight: Boolean): Integer; var R: TRect; P: TPoint; begin Indent := Trunc(Indent * RulerAdj); with Editor do begin SendMessage(Handle, EM_GETRECT, 0, Longint(@R)); if IsRight then begin P := R.BottomRight; P.X := P.X - Indent; end else begin P := R.TopLeft; P.X := P.X + Indent; end; P := ClientToScreen(P); end; with Ruler do P := ScreenToClient(P); Result := P.X; end; procedure TEditorMainForm.InsertBitmap(Sender: TObject); var Pict: TPicture; begin with FOpenPictureDialog do begin if Execute then begin Pict := TPicture.Create; try Pict.LoadFromFile(FileName); Clipboard.Assign(Pict); Editor.PasteFromClipboard; finally Pict.Free; end; end; end; end; procedure TEditorMainForm.InsertObject(Sender: TObject); begin Editor.InsertObjectDialog; end; procedure TEditorMainForm.ItalicButtonClick(Sender: TObject); begin if FUpdating then Exit; if ItalicBtn.Down then CurrText.Style := CurrText.Style + [fsItalic] else CurrText.Style := CurrText.Style - [fsItalic]; end; procedure TEditorMainForm.LeftIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FDragging := False; if FLineVisible then DrawLine; DeleteObject(SelectObject(FLineDC, FLinePen)); ReleaseDC(Editor.Handle, FLineDC); Editor.Paragraph.LeftIndent := Max(-Editor.Paragraph.FirstIndent, RulerToIndent(LeftInd.Left + FDragOfs, False) - Editor.Paragraph.FirstIndent); SelectionChange(Sender); end; procedure TEditorMainForm.MainMenuGetImageIndex(Sender: TMenu; Item: TMenuItem; State: TMenuOwnerDrawState; var ImageIndex: Integer); begin if Item.Tag >= 0 then ImageIndex := Item.Tag; end; procedure TEditorMainForm.PerformFileOpen(const AFileName: string); begin FProtectChanging := True; try Editor.Lines.LoadFromFile(AFileName); finally FProtectChanging := False; end; SetFileName(AFileName); Editor.SetFocus; Editor.Modified := False; SetModified(False); end; procedure TEditorMainForm.ProtectedItemClick(Sender: TObject); begin if FUpdating then Exit; FProtectChanging := True; try CurrText.Protected := not CurrText.Protected; ProtectedItem.Checked := CurrText.Protected; finally FProtectChanging := False; end; end; procedure TEditorMainForm.RichEditChange(Sender: TObject); begin SetModified(Editor.Modified); { Undo } UndoBtn.Enabled := Editor.CanUndo; EditUndoItem.Enabled := UndoBtn.Enabled; EditUndoItem.Caption := '&Undo ' + UndoNames[Editor.UndoName]; { Redo } EditRedoItem.Enabled := Editor.CanRedo; RedoBtn.Enabled := EditRedoItem.Enabled; EditRedoItem.Caption := '&Redo ' + UndoNames[Editor.RedoName]; end; procedure TEditorMainForm.RightIndMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FDragging := False; if FLineVisible then DrawLine; DeleteObject(SelectObject(FLineDC, FLinePen)); ReleaseDC(Editor.Handle, FLineDC); Editor.Paragraph.RightIndent := Max(0, RulerToIndent(RightInd.Left + FDragOfs, True)); SelectionChange(Sender); end; procedure TEditorMainForm.RulerItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FDragOfs := (TControl(Sender).Width div 2); TControl(Sender).Left := Max(0, TControl(Sender).Left + X - FDragOfs); FLineDC := GetDCEx(Editor.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS or DCX_LOCKWINDOWUPDATE); FLinePen := SelectObject(FLineDC, CreatePen(PS_DOT, 1, ColorToRGB(clWindowText))); SetROP2(FLineDC, R2_XORPEN); CalcLineOffset(TControl(Sender)); DrawLine; FDragging := True; end; procedure TEditorMainForm.RulerItemMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if FDragging then begin DrawLine; TControl(Sender).Left := Min(Max(0, TControl(Sender).Left + X - FDragOfs), Ruler.ClientWidth - FDragOfs * 2); CalcLineOffset(TControl(Sender)); DrawLine; end; end; procedure TEditorMainForm.RulerResize(Sender: TObject); begin RulerLine.Width := Ruler.ClientWidth - (RulerLine.Left * 2); end; function TEditorMainForm.RulerToIndent(RulerPos: Integer; IsRight: Boolean): Integer; var R: TRect; P: TPoint; begin P.Y := 0; P.X := RulerPos; with Ruler do P := ClientToScreen(P); with Editor do begin P := ScreenToClient(P); SendMessage(Handle, EM_GETRECT, 0, Longint(@R)); if IsRight then Result := R.BottomRight.X - P.X else Result := P.X - R.TopLeft.X; end; Result := Trunc(Result / RulerAdj); end; procedure TEditorMainForm.SelectFont(Sender: TObject); begin FontDialog.Font.Assign(Editor.SelAttributes); if FontDialog.Execute then CurrText.Assign(FontDialog.Font); FocusEditor; end; procedure TEditorMainForm.SelectionChange(Sender: TObject); begin with Editor.Paragraph do try FUpdating := True; FirstInd.Left := IndentToRuler(FirstIndent, False) - (FirstInd.Width div 2); LeftInd.Left := IndentToRuler(LeftIndent + FirstIndent, False) - (LeftInd.Width div 2); RightInd.Left := IndentToRuler(RightIndent, True) - (RightInd.Width div 2); BoldBtn.Down := fsBold in CurrText.Style; ItalicBtn.Down := fsItalic in CurrText.Style; UnderlineBtn.Down := fsUnderline in CurrText.Style; BulletsBtn.Down := Boolean(Numbering); SuperscriptBtn.Down := CurrText.SubscriptStyle = ssSuperscript; SubscriptBtn.Down := CurrText.SubscriptStyle = ssSubscript; FontSize.AsInteger := CurrText.Size; FontName.FontName := CurrText.Name; ProtectedItem.Checked := CurrText.Protected; DisabledItem.Checked := CurrText.Disabled; HiddenItem.Checked := CurrText.Hidden; case Ord(Alignment) of 0: LeftBtn.Down := True; 1: RightBtn.Down := True; 2: CenterBtn.Down := True; 3: JustifyBtn.Down := True; end; UpdateCursorPos; finally FUpdating := False; end; end; procedure TEditorMainForm.SetEditRect; var R: TRect; Offs: Integer; begin with Editor do begin if SelectionBar then Offs := 3 else Offs := 0; R := Rect(GutterWid + Offs, 0, ClientWidth - GutterWid, ClientHeight); SendMessage(Handle, EM_SETRECT, 0, Longint(@R)); end; end; procedure TEditorMainForm.SetFileName(const FileName: string); begin FFileName := FileName; Editor.Title := ExtractFileName(FileName); Caption := Format('%s - %s', [ExtractFileName(FileName), Application.Title]); end; procedure TEditorMainForm.SetModified(Value: Boolean); begin if Value then StatusBar.Panels[1].Text := 'Modified' else StatusBar.Panels[1].Text := ''; end; procedure TEditorMainForm.SetupRuler; var I: Integer; S: string; begin SetLength(S, 201); I := 1; while I < 200 do begin S[I] := #9; S[I + 1] := '|'; Inc(I, 2); end; Ruler.Caption := S; end; procedure TEditorMainForm.ShowHint(Sender: TObject); begin if Length(Application.Hint) > 0 then begin StatusBar.SimplePanel := True; StatusBar.SimpleText := Application.Hint; end else StatusBar.SimplePanel := False; end; procedure TEditorMainForm.SubscriptClick(Sender: TObject); begin if FUpdating then Exit; if SuperscriptBtn.Down then CurrText.SubscriptStyle := ssSuperscript else if SubscriptBtn.Down then CurrText.SubscriptStyle := ssSubscript else CurrText.SubscriptStyle := ssNone; end; procedure TEditorMainForm.UnderlineButtonClick(Sender: TObject); begin if FUpdating then Exit; if UnderlineBtn.Down then CurrText.Style := CurrText.Style + [fsUnderline] else CurrText.Style := CurrText.Style - [fsUnderline]; end; procedure TEditorMainForm.UpdateCursorPos; var CharPos: TPoint; begin CharPos := Editor.CaretPos; StatusBar.Panels[0].Text := Format('Line: %3d Col: %3d', [CharPos.Y + 1, CharPos.X + 1]); { update the status of the cut and copy command } CopyBtn.Enabled := Editor.SelLength > 0; EditCopyItem.Enabled := CopyBtn.Enabled; CopyItm.Enabled := CopyBtn.Enabled; CutBtn.Enabled := EditCopyItem.Enabled; CutItm.Enabled := CutBtn.Enabled; FileSaveSelItem.Enabled := CopyBtn.Enabled; EditCutItem.Enabled := EditCopyItem.Enabled; EditObjPropsItem.Enabled := Editor.SelectionType = [stObject]; end; procedure TEditorMainForm.DropFiles(DropHandle: Integer); var I: Cardinal; FileName: array[0..MAX_PATH + 1] of Char; CharRange: TCharRange; FileCount: LongWord; Code: Integer; begin FileCount := DragQueryFile(DropHandle, $FFFFFFFF, nil, 0); if FileCount = 0 then Exit else if FileCount = 1 then begin // load complete file DragQueryFile(DropHandle, 0, FileName, MAX_PATH); Application.BringToFront; CheckFileSave; PerformFileOpen(FileName); end else begin CharRange := Editor.GetSelection; for I := 0 to FileCount - 1 do begin DragQueryFile(DropHandle, I, FileName, MAX_PATH); Code := GetFileAttributes(FileName); if (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0) then Continue; Editor.SetSelection(CharRange.cpMax, CharRange.cpMax, False); Editor.InsertObjectFromFile(FileName, False); Inc(CharRange.cpMax); end; Editor.SetSelection(CharRange.cpMin, CharRange.cpMax, False); end; end; const IID_IMarshal: TGUID = ( D1:$00000003;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46)); procedure TEditorMainForm.EditorQueryAcceptData(Sender: TObject; const ADataObject: IDataObject; var AFormat: Word; ClipboardOperationKind: Cardinal; Really: Boolean; IconMetaPict: Cardinal; var Handled: Boolean); var FormatEtc: TFormatEtc; Medium: TStgMedium; begin // It is difficult to determine whether the drag started in our rich edit // control or somewhere else. Mainly because we don't get a finish event if the // drag is cancelled. If the ADataObject supports the IMarshall interface then // it probably comes from another process. FDragStartedHere := not Really and not Supports(ADataObject, IID_IMarshal); if Really then begin // Is the data the locations of a group of existing files? FormatEtc.cfFormat := CF_HDROP; FormatEtc.ptd := nil; FormatEtc.dwAspect := DVASPECT_CONTENT; FormatEtc.lindex := -1; FormatEtc.tymed := TYMED_HGLOBAL; if Succeeded(ADataObject.QueryGetData(FormatEtc)) then begin Medium.tymed := TYMED_NULL; Medium.hGlobal := 0; Medium.unkForRelease := nil; if Succeeded(ADataObject.GetData(FormatEtc, Medium)) then begin // Yes, group of files; we handle it ourself. Handled := True; DropFiles(HDROP(Medium.hGlobal)); ReleaseStgMedium(Medium); end; end; end; end; procedure TEditorMainForm.EditorGetDragDropEffect(Sender: TObject; ShiftState: TShiftState; var AllowedEffects: TRichDropEffects; var Handled: Boolean); var Effect: TRichDropEffect; begin // wordpad // // ctrl = copy // alt = move // ctrl + shift = link // // http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.dragover.aspx // // ctrl + alt = link // alt = link // shift = move // ctrl = copy if ShiftState * [ssCtrl, ssShift] = [ssCtrl, ssShift] then Effect := rdeLink else if ShiftState * [ssCtrl] = [ssCtrl] then Effect := rdeCopy else if ShiftState * [ssAlt] = [ssAlt] then Effect := rdeMove else begin // drag-drop from external application to this richedit should default be copy // drag-drop starting&ending in this richedit should default be move if FDragStartedHere then Effect := rdeMove else Effect := rdeCopy; end; if Effect in AllowedEffects then AllowedEffects := [Effect] else AllowedEffects := []; Handled := True; end; end.