Novel Unit

The code of the novel unit

unit Novel;
{
    Copyright (c) 2013 Jerzy Griffiths

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/ }
 
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  strutils, ShellAPI, Dialogs, ComCtrls, ExtCtrls, ToolWin, StdCtrls, Menus,
  AppEvnts, ImgList, inifiles, shlobj, Gauges, Grids, Calendar, richedit;

type
  TNovel_frm = class(TForm)
    ToolBar1: TToolBar;
    tbtn_New: TToolButton;
    tbtn_Save: TToolButton;
    tbtn_Print: TToolButton;
    ToolButton5: TToolButton;
    tbtn_Cut: TToolButton;
    tbtn_Copy: TToolButton;
    tbtn_Paste: TToolButton;
    tbtn_Undo: TToolButton;
    ToolButton21: TToolButton;
    tbtn_Bold: TToolButton;
    tbtn_Italic: TToolButton;
    ToolButton13: TToolButton;
    ComboFont: TComboBox;
    ToolButton1: TToolButton;
    ColorBox1: TColorBox;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Edit1: TMenuItem;
    Resources1: TMenuItem;
    Notes_menu_btn: TMenuItem;
    DeadlinePlanner1: TMenuItem;
    Options1: TMenuItem;
    WritingMode1: TMenuItem;
    New1: TMenuItem;
    menubtn_Open: TMenuItem;
    Save2: TMenuItem;
    SaveAs1: TMenuItem;
    Print1: TMenuItem;
    ExitProgramsavesonexit1: TMenuItem;
    Undo_menu_btn: TMenuItem;
    Cut_menu_btn: TMenuItem;
    Copy_menu_btn: TMenuItem;
    Paste_Menu_btn: TMenuItem;
    Wordcount: TMenuItem;
    Generalresources1: TMenuItem;
    ProjectResources1: TMenuItem;
    General_notes_menu_btn: TMenuItem;
    Project_notes_menu_btn: TMenuItem;
    ImageList1: TImageList;
    Tbtn_open: TToolButton;
    Tbtn_Underlined: TToolButton;
    Tbtn_redo: TToolButton;
    ToolButton3: TToolButton;
    tbtn_deadline_planner: TToolButton;
    tbtn_options: TToolButton;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    Text_Size_combo: TComboBox;
    NovelFile1: TMenuItem;
    Part1: TMenuItem;
    Chapter1: TMenuItem;
    Scene1: TMenuItem;
    Removefilefromproject1: TMenuItem;
    Richedit_menu: TPopupMenu;
    PopUpCut: TMenuItem;
    PopUpCopy: TMenuItem;
    PopUpPaste: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    N5: TMenuItem;
    N6: TMenuItem;
    N7: TMenuItem;
    Popupundo: TMenuItem;
    N8: TMenuItem;
    PopUpDelete: TMenuItem;
    N1: TMenuItem;
    PopUpSelectAll: TMenuItem;
    StatusBar1: TStatusBar;
    Panel1: TPanel;
    Chapter_page: TPageControl;
    TabSheet1: TTabSheet;
    RichEdit1: TRichEdit;
    Panel2: TPanel;
    TreeView1: TTreeView;
    Button1: TButton;
    Splitter1: TSplitter;
    PrintDialog1: TPrintDialog;
    Help1: TMenuItem;
    procedure Paste_Menu_btnClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure tbtn_BoldClick(Sender: TObject);
    procedure WritingMode1Click(Sender: TObject);
    procedure tbtn_deadline_plannerClick(Sender: TObject);
    procedure Undo_menu_btnClick(Sender: TObject);
    procedure Cut_menu_btnClick(Sender: TObject);
    procedure Copy_menu_btnClick(Sender: TObject);
    procedure Options1Click(Sender: TObject);
    procedure General_notes_menu_btnClick(Sender: TObject);
    procedure Project_notes_menu_btnClick(Sender: TObject);
    procedure Resources1Click(Sender: TObject);
    procedure Generalresources1Click(Sender: TObject);
    procedure ProjectResources1Click(Sender: TObject);
    procedure Tbtn_redoClick(Sender: TObject);
    procedure ColorBox1Change(Sender: TObject);
    procedure ComboFontChange(Sender: TObject);
    procedure Text_Size_comboChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
    procedure tbtn_ItalicClick(Sender: TObject);
    procedure Tbtn_UnderlinedClick(Sender: TObject);
    procedure Tbtn_openClick(Sender: TObject);
    procedure Save2Click(Sender: TObject);
    procedure SaveAs1Click(Sender: TObject);
    procedure TreeView1DblClick(Sender: TObject);
    procedure Part1Click(Sender: TObject);
    procedure Chapter1Click(Sender: TObject);
    procedure Scene1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
                               Shift: TShiftState; X, Y: integer);
    procedure PopUpDeleteClick(Sender: TObject);
    procedure Richedit_menuPopup(Sender: TObject);
    procedure PopUpSelectAllClick(Sender: TObject);
    procedure WordcountClick(Sender: TObject);
    procedure Print1Click(Sender: TObject);
    procedure RichEdit1KeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
    procedure tbtn_NewClick(Sender: TObject);
    procedure RichEdit1KeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
    procedure Splitter1Moved(Sender: TObject);
    procedure FormHide(Sender: TObject);
    procedure RichEdit1SelectionChange(Sender: TObject);
    procedure NovelFile1Click(Sender: TObject);
    procedure Help1Click(Sender: TObject);
    procedure ExitProgramsavesonexit1Click(Sender: TObject);
    procedure Removefilefromproject1Click(Sender: TObject);
  private
    { Private declarations }
  public
    open_file: boolean;
    File_save_path: string;
    target: integer;
    { Public declarations }
  end;

var
  Novel_frm: TNovel_frm;
  tabs, wordscount, Startwordcount, writingmodecount, writingmodestart,
  writingmodetarget: integer;
  tempcomp: TComponent;
  ClassName: TComponent;
  tabname: string;
  Writing_mode, creating: boolean;

implementation

uses deadline_planner, options, notes, resources, main_menu;

{$R *.dfm}

procedure Get_Active_Component;
var
  i: integer;
begin
  // insipration from http://www.festra.com/wwwboard/messages/2249.html
  if Novel_frm.activecontrol <> nil then
  begin
    for i := 0 to Novel_frm.ComponentCount - 1 do
    begin
      if (i > Novel_frm.ComponentCount - 1 - Novel_frm.Chapter_page.pagecount) then { as long as the active component is a richedit
        27 is the component number of richedit1, and as there are 64 components in the form,
        any created components will have a number greater than 64, and the only components
        created are richedits }
      begin
        if LowerCase(Novel_frm.Components[i].Name) = LowerCase(Novel_frm.activecontrol.Name) then
        begin // checks if the name of the component is equal to the active control
          tempcomp := Novel_frm.Components[i];
          // tempcomp is now equal to the active richedit
        end;
      end;
    end;
  end;
end;

procedure countwords;
var
  countword, character_count, pointer: integer;
  strings: string;
  i: integer;
begin
  countword := 0;
  wordscount := 0;
  for i := 0 to Novel_frm.Chapter_page.pagecount - 1 do
  begin
    tempcomp := Novel_frm.Components[Novel_frm.ComponentCount + i - Novel_frm.Chapter_page.pagecount];
    // Removes linebreaks, replacing them with spaces, and then trims all the excess spaces
    strings := trim(StringReplace((tempcomp as TRichEdit).Text, sLineBreak, ' ', [rfReplaceAll]));
    // Finds the length of the whole string, then minuses the length of the string minus spaces
    // then adds one to include the last word.
    pointer := 1;
    if strings <> '' then
    begin
      repeat
        if (strings[pointer] = ' ') and (strings[pointer + 1] = ' ') then
        begin
          Delete(strings, pointer, 1);
        end
        else
        begin
          Inc(pointer);
        end;
        character_count := length(strings);
      until pointer = character_count + 1;
      countword := length(strings) - length(StringReplace(strings, ' ', '', [rfReplaceAll])) + 1;
    end
    else
      countword := 0;
    wordscount := wordscount + countword;
    if Writing_mode = True then
    begin
      writingmodecount := wordscount - writingmodestart;
      Novel_frm.StatusBar1.panels[1].Text := 'Writing Mode Count: ' + IntToStr(writingmodecount);
      if writingmodecount = writingmodetarget then
      begin
        Novel_frm.BorderStyle := bssizeable;
        Novel_frm.WindowState := wsnormal;
        Novel_frm.formstyle := fsnormal;
        Novel_frm.tbtn_new.Enabled := True;
        Novel_frm.tbtn_save.Enabled := True;
        Novel_frm.tbtn_print.Enabled := True;
        Novel_frm.tbtn_cut.Enabled := True;
        Novel_frm.tbtn_copy.Enabled := True;
        Novel_frm.tbtn_paste.Enabled := True;
        Novel_frm.tbtn_undo.Enabled := True;
        Novel_frm.tbtn_redo.Enabled := True;
        Novel_frm.tbtn_bold.Enabled := True;
        Novel_frm.tbtn_italic.Enabled := True;
        Novel_frm.tbtn_underlined.Enabled := True;
        Novel_frm.tbtn_options.Enabled := True;
        Novel_frm.tbtn_deadline_planner.Enabled := True;
        Novel_frm.tbtn_open.Enabled := True;
        Novel_frm.ToolBar1.Enabled := True;
        Novel_frm.menu := Novel_frm.MainMenu1;
        Writing_mode := not Writing_mode;
      end;
    end;
    if (options_frm.Progress_deadline = 2) and (main_menu_frm.Saved_Before) then
      wordscount := wordscount - Startwordcount;
    Novel_frm.StatusBar1.panels[0].Text := format('Wordcount\Target: %s/%s', [IntToStr(wordscount),
                                                  IntToStr(Novel_frm.target)]);
  end;
end;

function BrowseDialog(const Title: string; const Flag: integer): string;
var
  lpItemID: PItemIDList;
  BrowseInfo: TBrowseInfo;
  DisplayName: array [0 .. MAX_PATH] of char;
  TempPath: array [0 .. MAX_PATH] of char;
begin
  Result := '';
  FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);
  with BrowseInfo do
  begin
    hwndOwner := Application.Handle;
    pszDisplayName := @DisplayName;
    lpszTitle := PChar(Title);
    ulFlags := Flag;
  end;
  lpItemID := SHBrowseForFolder(BrowseInfo);
  if lpItemID <> nil then
  begin
    SHGetPathFromIDList(lpItemID, TempPath);
    Result := IncludeTrailingBackslash(TempPath);
    GlobalFreePtr(lpItemID);
  end;
end;

procedure writingmode;
var
  input: string;
  Errorpos, checkint: integer;
begin
  { toggles writing mode on and off, if on then the form cannot be resized, nor exited
    as well as the fact that the form will stay on top }
  repeat
    input := inputbox('Writing Mode.',
      'How many words do you want to write in writingmode?', '1');
    val(input, checkint, Errorpos);
    if not Errorpos = 0 then
      ShowMessage('Please enter a valid integer number');
  until (input <> '') and (Errorpos = 0);
  Novel_frm.BorderStyle := bsnone;
  Novel_frm.WindowState := wsmaximized;
  Novel_frm.formstyle := fsstayontop;
  countwords;
  writingmodestart := wordscount;
  writingmodecount := 0;
  writingmodetarget := (StrToInt(input));
  Writing_mode := not Writing_mode;
  Novel_frm.ToolBar1.Enabled := False;
  Novel_frm.menu := nil;
end;

procedure Save_program();
var
  i: integer;
  node_count: integer;
  tabname: string;
  Ini: tinifile;
  myfile: textfile;
  jrgfile_path: string;
begin
  try
    if not main_menu_frm.Saved_Before then
    begin
      repeat
        if not inputquery('Saving...', 'Please choose the name of the project.',
                          main_menu_frm.filename) then
          exit;
      until main_menu_frm.filename <> '';
      jrgfile_path := BrowseDialog('Select a folder to save the shortcut file.', BIF_RETURNONLYFSDIRS);
      if jrgfile_path = '' then
        Exit;
      Novel_frm.File_save_path := format('%s%s\', [main_menu_frm.path, main_menu_frm.filename]);
      main_menu_frm.Saved_Before := True;
      // use File_save_path to get the place where ini file has to be saved to
      forcedirectories(format('%soptions\', [Novel_frm.File_save_path]));
      forcedirectories(format('%sDeadlines\', [Novel_frm.File_save_path]));
      Ini := tinifile.Create(Novel_frm.File_save_path + 'Options\Options.ini');
      Ini.writeinteger('Main Section', 'Type of file', 1);
      Ini.writeinteger('Main Section', 'Progress bar', 1);
    end;
    countwords;
    Ini.writeinteger('Main Section', 'Word Count', wordscount);
    // Use File_save_path to save the deadline planner and resources (notes will be on seperate form)
    // Save each tab into a new file at File_save_path
    if main_menu_frm.saved_before then
      deletefile(format('%sTreeview.txt', [Novel_frm.File_save_path]));

    Novel_frm.TreeView1.SaveToFile(format('%sTreeview.txt', [Novel_frm.File_save_path]));
    for i := 0 to Novel_frm.Chapter_page.pagecount - 1 do
    begin
      tempcomp := Novel_frm.Components[Novel_frm.ComponentCount + i - Novel_frm.Chapter_page.pagecount];
      tabname := format('%s%s.rtf', [Novel_frm.File_save_path, Novel_frm.Chapter_page.Pages[i].Caption]);
      if fileexists(tabname) then
      begin
        if deletefile(tabname) then
        else
          ShowMessage('Sorry, there has been an error overwriting the file so the program cannot save right now.');
      end;
      (tempcomp as TRichEdit).Lines.SaveToFile(tabname);
    end;
    ShowMessage('Saved program');
    Assign(myfile, format('%s\%s.jrg', [jrgfile_path, main_menu_frm.filename]));
    rewrite(myfile);
    writeln(myfile, 'JRG file');
    closefile(myfile);
    novel_frm.Caption := main_menu_frm.filename;
  except

  end;
end;

procedure Create_new_tab(Name_of_Tab: string);
var
  TabSheet: TTabSheet;
  // Pages: array of tabsheet;
  tabcount: integer;
  pagecount: string;
  i: integer;
label
  Exit_procedure;
begin
  if not creating then
  begin
    tabcount := Novel_frm.Chapter_page.pagecount;
    for i := 0 to tabcount - 1 do
    begin
      if LowerCase(Novel_frm.Chapter_page.Pages[i].Caption) =
        LowerCase(Novel_frm.TreeView1.selected.Text) then
      begin
        ShowMessage('That file is currently open');
        goto Exit_procedure;
      end;
    end;
  end;
  // code from http://stackoverflow.com/questions/12233205/dynamically-add-tab-sheets-to-page-control-and-embed-a-form
  // tab control - items belonged to contorl not tabs - page belongs to page, not control.
  TabSheet := TTabSheet.Create(Novel_frm.Chapter_page);
  TabSheet.Caption := Name_of_Tab;
  TabSheet.PageControl := Novel_frm.Chapter_page;
  tabcount := Novel_frm.Chapter_page.pagecount;
  pagecount := trim(StringReplace(name_of_tab, ' ', '', [rfReplaceAll]));
  // code from stackoverflow.com ends
  with TRichEdit.Create(Novel_frm) do
  begin
    parent := TabSheet;
    anchors := [akLeft, akTop, akRight, akBottom];
    alignwithmargins := True;
    Enabled := True;
    Visible := True;
    wanttabs := True;
    Width := Novel_frm.Chapter_page.Width - 3;
    Height := Novel_frm.Chapter_page.Height - 3;
    Name := pagecount + 'File';
    scrollbars := ssvertical;
    hidescrollbars := False;
    begin
      OnSelectionChange := Novel_frm.RichEdit1SelectionChange;
      onkeydown := Novel_frm.RichEdit1KeyDown;
      onmouseup := Novel_frm.RichEdit1MouseUp;
      onkeyup := Novel_frm.RichEdit1KeyUp;
    end;
    // Had left it as onkeypress so nthing was happening, resulting in no increase in word count
    if Novel_frm.open_file then
    begin
      Lines.LoadFromFile(format('%s%s\%s.rtf', [main_menu_frm.path,
                         main_menu_frm.filename, Name_of_Tab]));
      Novel_frm.open_file := False;
    end;

  end;
  tempcomp := Novel_frm.Components[59 + tabcount];
  creating := False;
  Exit_procedure: ;
end;

procedure TNovel_frm.Undo_menu_btnClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).undo; // undoes last action in active richedit
end;

procedure TNovel_frm.Text_Size_comboChange(Sender: TObject);
var
  Catchint, Errorpos: integer;
begin
  Get_Active_Component;
  try
    val(Text_Size_combo.Text, Catchint, Errorpos);
    if (Text_Size_combo.Text <> '') and (Errorpos = 0) then
    begin
      (tempcomp as TRichEdit).SelAttributes.Size :=
        StrToInt(Text_Size_combo.Text);
    end
    else
    begin
      ShowMessage('Invalid input');
    end;
  finally
  end;
end;

procedure TNovel_frm.TreeView1DblClick(Sender: TObject);
var
  To_open: string;
begin
  To_open := TreeView1.selected.Text;
  open_file := True;
  Create_new_tab(To_open);
end;

procedure TNovel_frm.Button1Click(Sender: TObject);
var
  Save, i: integer;
begin
  Get_Active_Component;
  Save := MessageDlg('Do you want to save the work?', mtConfirmation, mbyesno, 0);
  if (Save = mrYes) or (save = mrOk) and main_menu_frm.saved_before then
    save_program;
  Chapter_page.ActivePage.Destroy;
  // delete current tab
end;

procedure TNovel_frm.Chapter1Click(Sender: TObject);
var
  name_of_part: string;
  i: integer;
begin
  if TreeView1.selected <> nil then
  begin
    if TreeView1.selected.parent = nil then
    begin
      repeat
        name_of_part := inputbox('New Tab',
                                 'Please choose the name of the Chapter.', 'Untitled');
      until name_of_part <> '';
      for i := 0 to Novel_frm.TreeView1.items.Count - 1 do
        if LowerCase(Novel_frm.TreeView1.items[i].Text) = LowerCase(name_of_part) then
        begin
          ShowMessage('That file already exists.');
          exit;
        end;
      creating := True;
      Create_new_tab(name_of_part);
      TreeView1.items.addchild(TreeView1.selected, name_of_part);
      TreeView1.selected.expand(False);
    end;
  end
  else
    ShowMessage('Please select a Part to put the chapter in');
end;

procedure TNovel_frm.ColorBox1Change(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).SelAttributes.Color := ColorBox1.selected;
  // changes the colour of the selected text to the colourbox's selcted item
end;

procedure TNovel_frm.ComboFontChange(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).SelAttributes.Name := ComboFont.Text;
  // changes the font of the selected text to the combofont's selected item
end;

procedure TNovel_frm.Copy_menu_btnClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).copytoClipboard;
  // copies current text from active richedit
end;

procedure TNovel_frm.Cut_menu_btnClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).cuttoClipboard;
  // cuts the current text from the active richedit
end;

procedure TNovel_frm.ExitProgramsavesonexit1Click(Sender: TObject);
begin
  try
    novel_frm.Close;
    Main_Menu_frm.Exit_btnClick(Sender);
  except

  end;
end;

procedure TNovel_frm.PopUpDeleteClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).seltext := '';
end;

procedure TNovel_frm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
var
  Result: integer;
begin
  if Writing_mode = True then
    CanClose := False;
  // allows the user to close the form as long as writing mode isn't active
  Result := MessageDlg('Are you sure you want to Quit?',
    mtConfirmation, mbyesno, 0);
  if Result = mrYes then
    Canclose := True
  else
    CanClose := False;
end;

procedure TNovel_frm.FormCreate(Sender: TObject);
begin
  Text_Size_combo.Text := '9';
  tempcomp := RichEdit1; // enables combofont to be filled without an error
  { The next two lines fill the combofont listbox (the one in the quickbar)
    with all the fonts that the user has installed on the computer }
  ComboFont.items := Screen.Fonts;
  ComboFont.ItemIndex := ComboFont.items.IndexOf((tempcomp as TRichEdit).Font.Name);
  Novel_frm.Caption := main_menu_frm.filename;
end;

procedure TNovel_frm.FormHide(Sender: TObject);
var
  i: integer;
begin
  creating := True;
  Chapter_page.Pages[0].Destroy;
  Create_new_tab('Closing_tab');
  if chapter_page.PageCount > 1 then
  begin
    for i := Chapter_page.pagecount - 1 to 1 do
    begin
      Chapter_page.Pages[i].Destroy;
    end;
    TreeView1.items.Clear;
  end;
end;

procedure TNovel_frm.FormResize(Sender: TObject);
begin
  Panel1.Width := Novel_frm.Width - 150;
  if Novel_frm.Width <= 400 then
    ToolBar1.hide
  else
    ToolBar1.Show;
  if Novel_frm.Width <= 450 then
    Novel_frm.menu := nil
  else
    Novel_frm.menu := MainMenu1;
  { keeps the tab page (and therefore the richedits) in the same position in the
    form no matter what size it is, and also keeps the treeview's size 60 less than
    the form's height }
end;

procedure TNovel_frm.FormShow(Sender: TObject);
var
  s: string;
  Ini: tinifile;
  i: integer;
begin
  for i := chapter_page.PageCount - 1 downto 1 do
    chapter_page.Pages[i].Destroy;
  creating := True;
  Create_new_tab('new_tab');
  Chapter_page.Pages[0].Destroy;
  { Had these two statements the other way round, however
    If you destroy the last page in runtime it seems to destroy the tabpage, so couldn't
    create another one, so was throwing an error }

  if main_menu_frm.Saved_Before then
  begin
    TreeView1.LoadFromFile(format('%s%s\treeview.txt',
                                  [main_menu_frm.path, main_menu_frm.filename]));
    tempcomp := Novel_frm.Components[Novel_frm.ComponentCount - Chapter_page.pagecount];
    (tempcomp as TRichEdit).Lines.LoadFromFile(format('%s%s\%s.rtf',
                                               [main_menu_frm.path, main_menu_frm.filename, (TreeView1.items[0].Text)]));
    Chapter_page.Pages[0].Caption := TreeView1.items[0].Text;
    Ini := tinifile.Create(format('%s%s\Options\Options.ini', [main_menu_frm.path, main_menu_frm.filename]));
    target := Ini.readinteger('Main Section', 'Words', 0);
    Startwordcount := Ini.readinteger('Main Section', 'Word count', 0);
    file_save_path := main_menu_frm.path + main_menu_frm.filename + '\';
  end
  else
  begin
    repeat
      s := inputbox('New Novel File', 'Please choose the name of the first Part.', 'Untitled');
    until s <> '';
    treeview1.items.Clear;
    TreeView1.items.add(nil, s);
    Chapter_page.Pages[0].Caption := s;
    target := 0;
    Startwordcount := 0;
  end;
end;

procedure TNovel_frm.NovelFile1Click(Sender: TObject);
begin
  tbtn_NewClick(Sender);
end;

procedure TNovel_frm.Options1Click(Sender: TObject);
begin
  options_frm.general_options := False;
  options_frm.Show; // opens specific options page
end;

procedure TNovel_frm.Part1Click(Sender: TObject);
var
  name_of_part: string;
  i: integer;
begin
  repeat
    name_of_part := inputbox('New Tab', 'Please choose the name of the Part.', 'Untitled');
  until name_of_part <> '';
  for i := 0 to Novel_frm.TreeView1.items.Count - 1 do
  begin
    if LowerCase(Novel_frm.TreeView1.items[i].Text) = LowerCase(name_of_part) then
    begin
      ShowMessage('That file already exists.');
      Exit;
    end;
  end;
  creating := True;
  Create_new_tab(name_of_part);
  TreeView1.items.add(nil, name_of_part);
end;

procedure TNovel_frm.PopUpSelectAllClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).SelectAll;
end;

procedure TNovel_frm.Paste_Menu_btnClick(Sender: TObject);
begin
  Get_Active_Component;
  (tempcomp as TRichEdit).PasteFromClipboard; // pastes into the active richedit
end;

procedure TNovel_frm.Print1Click(Sender: TObject);
begin
  get_active_component();
  if ((tempcomp as trichedit).SelLength <> 0) then
  begin
    PrintDialog1.PrintRange := prSelection;
  end
  else
    PrintDialog1.PrintRange := prAllPages;
  if PrintDialog1.Execute then
  begin
    Get_Active_Component;
    (tempcomp as TRichEdit).Print(main_menu_frm.filename);
  end;
end;

procedure TNovel_frm.ProjectResources1Click(Sender: TObject);
begin
  resources_frm.general_resources := False;
  resources_frm.Show;
  // opens project specific resources
end;

procedure TNovel_frm.Project_notes_menu_btnClick(Sender: TObject);
begin
  notes_frm.general_notes := False;
  notes_frm.Show;
  // opens project specific notes
end;

procedure TNovel_frm.Generalresources1Click(Sender: TObject);
begin
  resources_frm.general_resources := True;
  resources_frm.Show;
  // opens the resources form with the general resources
end;

procedure TNovel_frm.General_notes_menu_btnClick(Sender: TObject);
begin
  notes_frm.general_notes := True;
  notes_frm.Show;
  // opens the general notes, and so on open the form will change slightly.
end;

procedure TNovel_frm.Help1Click(Sender: TObject);
begin
  main_menu_frm.Openhelpfile;
end;

procedure TNovel_frm.Removefilefromproject1Click(Sender: TObject);
var
  delete_path, Caption: string;
  i: integer;
begin
  Caption := chapter_page.pages[chapter_page.ActivePageindex].Caption;
  Delete_path := format('%s%s\%s.rtf', [main_menu_frm.path, main_menu_frm.filename, Caption]);
  Button1Click(Sender);
  if fileexists(delete_path) then
    if deletefile(delete_path) then
      ShowMessage('File successfully deleted');
  for i := 0 to treeview1.Items.Count do
    if treeview1.Items.Item[i].Text = Caption then
    begin
      treeview1.Items.Item[i].Destroy;
      exit;
    end;

end;

procedure TNovel_frm.Resources1Click(Sender: TObject);
begin
  resources_frm.general_resources := True;
  resources_frm.Show; // shows the general resources form
end;

procedure TNovel_frm.RichEdit1KeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  Get_active_component;
  if (key = 8) and ((tempcomp as trichedit).Text = '') then
  begin
    ShowMessage('Nothing to delete!');
    exit;
  end;
  RichEdit1SelectionChange(Sender);
end;

procedure TNovel_frm.RichEdit1KeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  countwords;
end;

procedure TNovel_frm.RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
                                      Shift: TShiftState; X, Y: integer);
begin
  if Button = mbright then
  begin
    Richedit_menu.popup(X + Novel_frm.Left, Y + Novel_frm.top);
  end;
end;

procedure TNovel_frm.RichEdit1SelectionChange(Sender: TObject);
begin
  if Novel_frm.Visible then
  begin
    Get_Active_Component;
    Novel_frm.tbtn_Bold.down := fsbold in (tempcomp as TRichEdit).SelAttributes.style;
    Novel_frm.tbtn_Italic.down := fsitalic in (tempcomp as TRichEdit).SelAttributes.style;
    Novel_frm.Tbtn_Underlined.down := fsunderline in (tempcomp as TRichEdit).SelAttributes.style;
    // checks what format the current text is, and toggles the bold, italic and
    // underline button accordingly
    Novel_frm.ComboFont.ItemIndex := ComboFont.Items.IndexOf((tempcomp as TRichEdit).SelAttributes.Name);
    Novel_frm.ColorBox1.selected := (tempcomp as TRichEdit).SelAttributes.Color;
    Novel_frm.Text_Size_combo.Text := IntToStr((tempcomp as TRichEdit).SelAttributes.Size);
  end;
end;

procedure TNovel_frm.Richedit_menuPopup(Sender: TObject);
begin
  if (tempcomp as TRichEdit).seltext = '' then
  begin
    PopUpCut.Enabled := False;
    PopUpCopy.Enabled := False;
    PopUpDelete.Enabled := False;
  end
  else
  begin
    PopUpCut.Enabled := True;
    PopUpCopy.Enabled := True;
    PopUpDelete.Enabled := True;
  end;
end;

procedure TNovel_frm.Save2Click(Sender: TObject);
begin
  Save_program;
end;

procedure TNovel_frm.SaveAs1Click(Sender: TObject);
begin
  main_menu_frm.Saved_Before := False;
  Save_program();
  // Choose place to save
end;

procedure TNovel_frm.Scene1Click(Sender: TObject);
var
  name_of_part: string;
  i: integer;
begin
  if TreeView1.selected <> nil then
  begin
    if TreeView1.selected.parent <> nil then
    begin
      repeat
        name_of_part := inputbox('New Tab', 'Please choose the name of the Scene.', 'Untitled');
      until name_of_part <> '';
      ;
      for i := 0 to Novel_frm.TreeView1.items.Count - 1 do
      begin
        if LowerCase(Novel_frm.TreeView1.items[i].Text) =
          LowerCase(name_of_part) then
        begin
          ShowMessage('That file already exists.');
          Exit;
        end;
      end;
      creating := True;
      Create_new_tab(name_of_part);
      TreeView1.items.addchild(TreeView1.selected, name_of_part);
      TreeView1.selected.expand(False);
    end
    else
      ShowMessage('Please select a chapter for the scene to be added to.');
  end;
end;

procedure TNovel_frm.Splitter1Moved(Sender: TObject);
begin
  if Panel2.Width <= 0 then
    Panel2.Width := 10;
  Panel1.Width := Novel_frm.Width - Splitter1.Width - Panel2.Width - 8;
end;

procedure TNovel_frm.tbtn_BoldClick(Sender: TObject);
begin
  Get_Active_Component;
  if fsbold in (tempcomp as TRichEdit).SelAttributes.style then
    // toggles bold on/off for selected text; removes it if on, and adds if off
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style - [fsbold]
  else
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style + [fsbold];
end;

procedure TNovel_frm.tbtn_ItalicClick(Sender: TObject);
begin
  Get_Active_Component;
  if fsitalic in (tempcomp as TRichEdit).SelAttributes.style then
    { was originally (tempcomp as trichedit).selattributes.style = [fsitalic] however,
      this meant that if if were more than just italic then it wouldn't work (same for bold
      and underline functions). At the moment, the code toggles the current text in and out
      of italic, checks if it is and then removes, or adds accordingly }
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style - [fsitalic]
  else
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style + [fsitalic];
end;

procedure TNovel_frm.tbtn_NewClick(Sender: TObject);
var
  Result, i: integer;
  input: string;
begin
  Result := MessageDlg('Are you sure you want to start a new project? (Will not save!)',
                       mtConfirmation, mbyesno, 0);
  try
    if Result = mrYes then
    begin
      repeat
        input := inputbox('Name of new project.', 'What would you like to name it?', 'Untitled');
      until input <> '';
      Creating := True;
      Create_new_tab(input);
      for i := Chapter_page.pagecount - 2 downto 0 do
      begin
        Chapter_page.Pages[i].Destroy;
      end;
      TreeView1.items.Clear;
      Treeview1.Items.Add(nil, input);
      main_menu_frm.Saved_Before := False;
    end
    else
    begin
      Exit;
    end;
  except

  end;
end;

procedure TNovel_frm.Tbtn_openClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    main_menu_frm.opened_with := OpenDialog1.filename;
    Novel_frm.hide;
    main_menu_frm.open_file;
  end;
end;

procedure TNovel_frm.Tbtn_redoClick(Sender: TObject);
begin
  Get_Active_Component;
  sendmessage((tempcomp as TRichEdit).handle, EM_redo, 0, 0); // undoes the last undo
  // for now, only one undo is possible, however, time permitting, I shall try and make this a larger number.
end;

procedure TNovel_frm.Tbtn_UnderlinedClick(Sender: TObject);
begin
  Get_Active_Component;
  if fsunderline in (tempcomp as TRichEdit).SelAttributes.style then
    // checks if the current text is underlined
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style - [fsunderline]
  // if yes, it makes the text not underlines
  else // and if not, it sets it to underlined
    (tempcomp as TRichEdit).SelAttributes.style := (tempcomp as TRichEdit).SelAttributes.style + [fsunderline];
end;

procedure TNovel_frm.tbtn_deadline_plannerClick(Sender: TObject);
begin
  if main_menu_frm.Saved_Before = True then
    deadline_planner_frm.Show
  else
    ShowMessage('You have not saved this before.');
  // shows the deadline planner so you can plan out your novel
end;

procedure TNovel_frm.WordcountClick(Sender: TObject);
begin
  countwords;
end;

procedure TNovel_frm.WritingMode1Click(Sender: TObject);
begin
  writingmode; // enters writing mode which will shut out distractions
end;

end.
Programming - a skill for life!

by Jerzy Griffiths: L6 Age ~17