Revision | 22 (tree) |
---|---|
Zeit | 2017-06-05 03:29:00 |
Autor | twm |
(empty log message)
@@ -0,0 +1,319 @@ | ||
1 | +unit wf_NoteEditor; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + StdCtrls, | |
14 | + ExtCtrls, | |
15 | + Menus, | |
16 | + CheckLst, | |
17 | + u_DenkzettelUtils; | |
18 | + | |
19 | +type | |
20 | + | |
21 | + TNoteDisplay = (ndMemo, ndChecklist); | |
22 | + | |
23 | + { Tfr_NoteEditor } | |
24 | + | |
25 | + Tfr_NoteEditor = class(TFrame) | |
26 | + b_Back: TButton; | |
27 | + b_Menu: TButton; | |
28 | + clb_Content: TCheckListBox; | |
29 | + ed_Title: TEdit; | |
30 | + mi_ChangeColor: TMenuItem; | |
31 | + mi_ToggleChecklist: TMenuItem; | |
32 | + m_Content: TMemo; | |
33 | + pm_Main: TPopupMenu; | |
34 | + p_Top: TPanel; | |
35 | + procedure b_BackClick(Sender: TObject); | |
36 | + procedure b_MenuClick(Sender: TObject); | |
37 | + procedure FrameEnter(Sender: TObject); | |
38 | + procedure mi_ChangeColorClick(Sender: TObject); | |
39 | + procedure mi_ToggleChecklistClick(Sender: TObject); | |
40 | + private | |
41 | + FControls: array[TNoteDisplay] of TControl; | |
42 | + FFilename: string; | |
43 | + FOnClose: TNotifyEvent; | |
44 | + FOrigContent: string; | |
45 | + FNoteColor: TDenkzettelColor; | |
46 | + function BuildFilename: string; | |
47 | + function IsChecklist: boolean; | |
48 | + function ContentHasChanged: boolean; | |
49 | + procedure doOnClose; | |
50 | + procedure GetContent(out _s: string); | |
51 | + procedure SetContent(const _s: string); | |
52 | + procedure SaveNote; | |
53 | + procedure SwitchDisplay(_Display: TNoteDisplay); | |
54 | + public | |
55 | + constructor Create(_Owner: TComponent); override; | |
56 | + procedure Init(const _fn: string); | |
57 | + procedure FormCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
58 | + procedure GoBack; | |
59 | + procedure ShowMenu; | |
60 | + property OnClose: TNotifyEvent read FOnClose write FOnClose; | |
61 | + end; | |
62 | + | |
63 | +implementation | |
64 | + | |
65 | +{$R *.lfm} | |
66 | + | |
67 | +uses | |
68 | + Dialogs, | |
69 | + Graphics, | |
70 | + strutils, | |
71 | + u_dzLazUtils, | |
72 | + w_SelectColor; | |
73 | + | |
74 | +{ Tfr_NoteEditor } | |
75 | + | |
76 | +constructor Tfr_NoteEditor.Create(_Owner: TComponent); | |
77 | +begin | |
78 | + inherited Create(_Owner); | |
79 | + | |
80 | + b_Menu.Caption := TRICOLON; | |
81 | + FControls[ndMemo] := m_Content; | |
82 | + FControls[ndChecklist] := clb_Content; | |
83 | +end; | |
84 | + | |
85 | +procedure Tfr_NoteEditor.Init(const _fn: string); | |
86 | +var | |
87 | + Title: string; | |
88 | + lIsCheckList: boolean; | |
89 | + sl: TStringList; | |
90 | + cl: TColor; | |
91 | +begin | |
92 | + FFilename := _fn; | |
93 | + DecodeFilename(_fn, Title, lIsCheckList, FNoteColor); | |
94 | + ed_Title.Text := Title; | |
95 | + cl := NoteColorToColor(FNoteColor, False); | |
96 | + ed_Title.Color := cl; | |
97 | + m_Content.Color := cl; | |
98 | + if lIsCheckList then | |
99 | + SwitchDisplay(ndChecklist) | |
100 | + else | |
101 | + SwitchDisplay(ndMemo); | |
102 | + sl := TStringList.Create; | |
103 | + try | |
104 | + sl.LoadFromFile(FFilename); | |
105 | + FOrigContent := sl.Text; | |
106 | + SetContent(FOrigContent); | |
107 | + finally | |
108 | + FreeAndNil(sl); | |
109 | + end; | |
110 | +end; | |
111 | + | |
112 | +procedure Tfr_NoteEditor.doOnClose; | |
113 | +var | |
114 | + CanClose: boolean; | |
115 | +begin | |
116 | + CanClose := True; | |
117 | + FormCloseQuery(Self, CanClose); | |
118 | + if CanClose then begin | |
119 | + if Assigned(FOnClose) then | |
120 | + FOnClose(Self); | |
121 | + end; | |
122 | +end; | |
123 | + | |
124 | +procedure Tfr_NoteEditor.b_BackClick(Sender: TObject); | |
125 | +begin | |
126 | + GoBack; | |
127 | +end; | |
128 | + | |
129 | +procedure Tfr_NoteEditor.b_MenuClick(Sender: TObject); | |
130 | +begin | |
131 | + ShowMenu; | |
132 | +end; | |
133 | + | |
134 | +procedure Tfr_NoteEditor.FrameEnter(Sender: TObject); | |
135 | +begin | |
136 | + TWinControl_SetFocus(m_Content); | |
137 | +end; | |
138 | + | |
139 | +procedure Tfr_NoteEditor.mi_ChangeColorClick(Sender: TObject); | |
140 | +var | |
141 | + dc: TDenkzettelColor; | |
142 | + cl: TColor; | |
143 | +begin | |
144 | + dc := dcWhite; | |
145 | + if Tf_SelectColor.Execute(Self, dc) then begin | |
146 | + FNoteColor := dc; | |
147 | + cl := NoteColorToColor(dc, False); | |
148 | + ed_Title.Color := cl; | |
149 | + m_Content.Color := cl; | |
150 | + end; | |
151 | +end; | |
152 | + | |
153 | +procedure Tfr_NoteEditor.SwitchDisplay(_Display: TNoteDisplay); | |
154 | +var | |
155 | + s: string; | |
156 | +begin | |
157 | + GetContent(s); | |
158 | + m_Content.Visible := False; | |
159 | + clb_Content.Visible := False; | |
160 | + FControls[_Display].Visible := True;; | |
161 | + SetContent(s); | |
162 | + | |
163 | + TWinControl_SetFocus(m_Content); | |
164 | +end; | |
165 | + | |
166 | +procedure Tfr_NoteEditor.GetContent(out _s: string); | |
167 | +var | |
168 | + i: integer; | |
169 | + s: string; | |
170 | + sl: TStringList; | |
171 | +begin | |
172 | + sl := TStringList.Create; | |
173 | + try | |
174 | + if m_Content.Visible then begin | |
175 | + sl.Assign(m_Content.Lines); | |
176 | + end else if clb_Content.Visible then begin | |
177 | + for i := 0 to clb_Content.Items.Count - 1 do begin | |
178 | + s := clb_Content.Items[i]; | |
179 | + if clb_Content.Checked[i] then | |
180 | + s := '- ' + s | |
181 | + else | |
182 | + s := '+ ' + s; | |
183 | + sl.Add(s); | |
184 | + end; | |
185 | + end else | |
186 | + raise Exception.Create('Either the memo or the checklist must be visible'); | |
187 | + _s := sl.Text; | |
188 | + finally | |
189 | + FreeAndNil(sl) | |
190 | + end; | |
191 | +end; | |
192 | + | |
193 | +procedure Tfr_NoteEditor.SetContent(const _s: string); | |
194 | +var | |
195 | + i, Idx: integer; | |
196 | + s: string; | |
197 | + sl: TStringList; | |
198 | +begin | |
199 | + sl := TStringList.Create; | |
200 | + try | |
201 | + sl.Text := _s; | |
202 | + if m_Content.Visible then begin | |
203 | + m_Content.Lines.Assign(sl); | |
204 | + end else if clb_Content.Visible then begin | |
205 | + clb_Content.Items.Clear; | |
206 | + for i := 0 to sl.Count - 1 do begin | |
207 | + s := sl[i]; | |
208 | + if s <> '' then begin | |
209 | + if AnsiStartsText('+ ', s) then begin | |
210 | + Idx := clb_Content.Items.Add(Copy(s, 3)); | |
211 | + end else if AnsiStartsText('- ', s) then begin | |
212 | + Idx := clb_Content.Items.Add(Copy(s, 3)); | |
213 | + clb_Content.Checked[Idx] := True; | |
214 | + end else begin | |
215 | + clb_Content.Items.Add(s); | |
216 | + end; | |
217 | + end; | |
218 | + end; | |
219 | + end else | |
220 | + raise Exception.Create('Either the memo or the checklist must be visible'); | |
221 | + finally | |
222 | + FreeAndNil(sl); | |
223 | + end; | |
224 | +end; | |
225 | + | |
226 | +procedure Tfr_NoteEditor.mi_ToggleChecklistClick(Sender: TObject); | |
227 | +begin | |
228 | + if IsChecklist then | |
229 | + SwitchDisplay(ndMemo) | |
230 | + else | |
231 | + SwitchDisplay(ndChecklist); | |
232 | +end; | |
233 | + | |
234 | +procedure Tfr_NoteEditor.GoBack; | |
235 | +begin | |
236 | + doOnClose; | |
237 | +end; | |
238 | + | |
239 | +procedure Tfr_NoteEditor.ShowMenu; | |
240 | +begin | |
241 | + TButton_DrowpdownMenu(b_Menu, pm_Main); | |
242 | +end; | |
243 | + | |
244 | +function Tfr_NoteEditor.IsChecklist: boolean; | |
245 | +begin | |
246 | + Result := clb_Content.Visible; | |
247 | +end; | |
248 | + | |
249 | +function Tfr_NoteEditor.BuildFilename: string; | |
250 | +var | |
251 | + DirBS, ext: RawByteString; | |
252 | +begin | |
253 | + Result := EncodeFilename(ed_Title.Text, clb_Content.Visible, FNoteColor); | |
254 | + DirBS := IncludeTrailingPathDelimiter(ExtractFileDir(FFilename)); | |
255 | + ext := ExtractFileExt(FFilename); | |
256 | + Result := DirBS + Result + ext; | |
257 | +end; | |
258 | + | |
259 | +function Tfr_NoteEditor.ContentHasChanged: boolean; | |
260 | +var | |
261 | + fn, s: string; | |
262 | +begin | |
263 | + fn := BuildFilename; | |
264 | + Result := True; | |
265 | + if fn <> FFilename then | |
266 | + Exit; //==> | |
267 | + GetContent(s); | |
268 | + Result := (s <> FOrigContent); | |
269 | +end; | |
270 | + | |
271 | +procedure Tfr_NoteEditor.SaveNote; | |
272 | +var | |
273 | + fn: string; | |
274 | + s: string; | |
275 | + sl: TStringList; | |
276 | + Center: TPoint; | |
277 | +begin | |
278 | + fn := BuildFilename; | |
279 | + if FFilename <> fn then begin | |
280 | + if not RenameFile(FFilename, fn) then begin | |
281 | + Center := TControl_GetParentFormCenter(Self); | |
282 | + MessageDlgPos('Renaming the file failed. Please make sure that your title is a valid file name!', | |
283 | + mtError, [mbOK], 0, Center.x, center.y); | |
284 | + SysUtils.Abort; | |
285 | + end; | |
286 | + FFilename := fn; | |
287 | + end; | |
288 | + sl := TStringList.Create; | |
289 | + try | |
290 | + GetContent(s); | |
291 | + sl.Text := s; | |
292 | + sl.SaveToFile(FFilename); | |
293 | + finally | |
294 | + FreeAndNil(sl); | |
295 | + end; | |
296 | +end; | |
297 | + | |
298 | +procedure Tfr_NoteEditor.FormCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
299 | +var | |
300 | + Center: TPoint; | |
301 | + Res: TModalResult; | |
302 | +begin | |
303 | + if not ContentHasChanged then | |
304 | + Exit; //==> | |
305 | + | |
306 | + Center := TControl_GetParentFormCenter(Self); | |
307 | + Res := MessageDlgPos('You have unsaved changes. Do you want to save them?', | |
308 | + mtConfirmation, [mbYes, mbNo, mbCancel], 0, Center.x, center.y); | |
309 | + case Res of | |
310 | + mrYes: begin | |
311 | + SaveNote; | |
312 | + end; | |
313 | + mrNo: ; | |
314 | + else | |
315 | + _CanClose := False; | |
316 | + end; | |
317 | +end; | |
318 | + | |
319 | +end. |
@@ -0,0 +1,242 @@ | ||
1 | +unit wf_Notes; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + Types, | |
11 | + FileUtil, | |
12 | + Forms, | |
13 | + Controls, | |
14 | + StdCtrls, | |
15 | + ExtCtrls, | |
16 | + Menus, | |
17 | + wf_NoteEditor; | |
18 | + | |
19 | +type | |
20 | + | |
21 | + { Tfr_Notes } | |
22 | + | |
23 | + Tfr_Notes = class(TFrame) | |
24 | + b_Menu: TButton; | |
25 | + pm_Main: TPopupMenu; | |
26 | + mi_About: TMenuItem; | |
27 | + mi_NewNote: TMenuItem; | |
28 | + b_Back: TButton; | |
29 | + lb_Notes: TListBox; | |
30 | + p_Main: TPanel; | |
31 | + p_Top: TPanel; | |
32 | + procedure FrameEnter(Sender: TObject); | |
33 | + procedure lb_NotesDrawItem(Control: TWinControl; Index: integer; | |
34 | + ARect: TRect; State: TOwnerDrawState); | |
35 | + procedure mi_AboutClick(Sender: TObject); | |
36 | + procedure b_BackClick(Sender: TObject); | |
37 | + procedure b_MenuClick(Sender: TObject); | |
38 | + procedure act_NewNoteExecute(Sender: TObject); | |
39 | + procedure lb_NotesDblClick(Sender: TObject); | |
40 | + procedure lb_NotesKeyPress(Sender: TObject; var Key: char); | |
41 | + private | |
42 | + FCategory: string; | |
43 | + FCategoryPathBS: string; | |
44 | + FOnClose: TNotifyEvent; | |
45 | + FEditFrame: Tfr_NoteEditor; | |
46 | + procedure doOnClose; | |
47 | + procedure OnCloseNote(_Sender: TObject); | |
48 | + function TryGetNoteFn(out _Note: string): boolean; | |
49 | + public | |
50 | + constructor Create(_Owner: TComponent); override; | |
51 | + procedure Init(const _Category: string; const _CategoryPath: string); | |
52 | + procedure FormCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
53 | + procedure GoBack; | |
54 | + procedure OpenSelected; | |
55 | + procedure ShowMenu; | |
56 | + property OnClose: TNotifyEvent read FOnClose write FOnClose; | |
57 | + end; | |
58 | + | |
59 | +implementation | |
60 | + | |
61 | +{$R *.lfm} | |
62 | + | |
63 | +uses | |
64 | + Graphics, | |
65 | + LCLType, | |
66 | + u_dzLazUtils, | |
67 | + u_DenkzettelUtils, | |
68 | + w_About; | |
69 | + | |
70 | +{ Tfr_Notes } | |
71 | + | |
72 | +constructor Tfr_Notes.Create(_Owner: TComponent); | |
73 | +begin | |
74 | + inherited Create(_Owner); | |
75 | + | |
76 | + b_Menu.Caption := TRICOLON; | |
77 | + | |
78 | + FEditFrame := Tfr_NoteEditor.Create(Self); | |
79 | + FEditFrame.Visible := False; | |
80 | + FEditFrame.Parent := Self; | |
81 | + FEditFrame.Align := alClient; | |
82 | + FEditFrame.OnClose := @OnCloseNote; | |
83 | +end; | |
84 | + | |
85 | +procedure Tfr_Notes.Init(const _Category: string; const _CategoryPath: string); | |
86 | +var | |
87 | + Files: TStringList; | |
88 | + i: integer; | |
89 | + fn, Title: string; | |
90 | + IsChecklist: boolean; | |
91 | + NoteColor: TDenkzettelColor; | |
92 | +begin | |
93 | + FCategory := _Category; | |
94 | + FCategoryPathBS := IncludeTrailingPathDelimiter(_CategoryPath); | |
95 | + p_Top.Caption := _Category; | |
96 | + | |
97 | + lb_Notes.Items.Clear; | |
98 | + Files := TStringList.Create; | |
99 | + try | |
100 | + EnumFiles(FCategoryPathBS, '*.txt', Files, True, False); | |
101 | + for i := 0 to Files.Count - 1 do begin | |
102 | + fn := files[i]; | |
103 | + fn := ChangeFileExt(fn, ''); | |
104 | + if not DecodeFilename(fn, Title, IsChecklist, NoteColor) then | |
105 | + Title := fn; | |
106 | + lb_Notes.Items.AddObject(Title, TObject(PropertiesToPointer(NoteColor, IsChecklist))); | |
107 | + end; | |
108 | + finally | |
109 | + FreeAndNil(Files); | |
110 | + end; | |
111 | + TWinControl_SetFocus(lb_Notes); | |
112 | +end; | |
113 | + | |
114 | +procedure Tfr_Notes.OnCloseNote(_Sender: TObject); | |
115 | +begin | |
116 | + FEditFrame.Visible := False; | |
117 | + p_Main.Visible := True; | |
118 | + Init(FCategory, FCategoryPathBS); | |
119 | +end; | |
120 | + | |
121 | +procedure Tfr_Notes.FormCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
122 | +begin | |
123 | + if not FEditFrame.Visible then | |
124 | + Exit; //==> | |
125 | + FEditFrame.FormCloseQuery(_Sender, _CanClose); | |
126 | +end; | |
127 | + | |
128 | +function Tfr_Notes.TryGetNoteFn(out _Note: string): boolean; | |
129 | +var | |
130 | + Idx: integer; | |
131 | + s: string; | |
132 | +begin | |
133 | + Result := False; | |
134 | + Idx := lb_Notes.ItemIndex; | |
135 | + if Idx = -1 then | |
136 | + Exit; //==> | |
137 | + s := lb_Notes.Items[Idx]; | |
138 | + if s = '' then | |
139 | + Exit; //==> | |
140 | + Result := FindMatchingFile(FCategoryPathBS + s + '*.*', _Note) > 0; | |
141 | +end; | |
142 | + | |
143 | +procedure Tfr_Notes.doOnClose; | |
144 | +begin | |
145 | + if Assigned(FOnClose) then | |
146 | + FOnClose(Self); | |
147 | +end; | |
148 | + | |
149 | +procedure Tfr_Notes.OpenSelected; | |
150 | +var | |
151 | + fn: string; | |
152 | +begin | |
153 | + if not Assigned(FEditFrame) then | |
154 | + Exit; //==> | |
155 | + if not TryGetNoteFn(fn) then | |
156 | + Exit; //==> | |
157 | + FEditFrame.Init(fn); | |
158 | + FEditFrame.Visible := True; | |
159 | + p_Main.Visible := False; | |
160 | +end; | |
161 | + | |
162 | +procedure Tfr_Notes.lb_NotesDblClick(Sender: TObject); | |
163 | +begin | |
164 | + OpenSelected; | |
165 | +end; | |
166 | + | |
167 | +procedure Tfr_Notes.lb_NotesKeyPress(Sender: TObject; var Key: char); | |
168 | +begin | |
169 | + if Key in [#13, #10] then | |
170 | + OpenSelected; | |
171 | +end; | |
172 | + | |
173 | +procedure Tfr_Notes.b_BackClick(Sender: TObject); | |
174 | +begin | |
175 | + doOnClose; | |
176 | +end; | |
177 | + | |
178 | +procedure Tfr_Notes.GoBack; | |
179 | +begin | |
180 | + if Assigned(FEditFrame) and FEditFrame.Visible then | |
181 | + FEditFrame.GoBack | |
182 | + else begin | |
183 | + doOnClose; | |
184 | + end; | |
185 | +end; | |
186 | + | |
187 | +procedure Tfr_Notes.ShowMenu; | |
188 | +begin | |
189 | + if Assigned(FEditFrame) and FEditFrame.Visible then | |
190 | + FEditFrame.ShowMenu | |
191 | + else begin | |
192 | + TButton_DrowpdownMenu(b_Menu, pm_Main); | |
193 | + end; | |
194 | +end; | |
195 | + | |
196 | +procedure Tfr_Notes.b_MenuClick(Sender: TObject); | |
197 | +begin | |
198 | + ShowMenu; | |
199 | +end; | |
200 | + | |
201 | +procedure Tfr_Notes.act_NewNoteExecute(Sender: TObject); | |
202 | +begin | |
203 | + // | |
204 | +end; | |
205 | + | |
206 | +procedure Tfr_Notes.mi_AboutClick(Sender: TObject); | |
207 | +begin | |
208 | + Tf_About.Execute(Self); | |
209 | +end; | |
210 | + | |
211 | +procedure Tfr_Notes.FrameEnter(Sender: TObject); | |
212 | +begin | |
213 | + TWinControl_SetFocus(lb_Notes); | |
214 | + if lb_Notes.ItemIndex = -1 then | |
215 | + if lb_Notes.Items.Count > 0 then | |
216 | + lb_Notes.ItemIndex := 0; | |
217 | +end; | |
218 | + | |
219 | +procedure Tfr_Notes.lb_NotesDrawItem(Control: TWinControl; Index: integer; | |
220 | + ARect: TRect; State: TOwnerDrawState); | |
221 | +var | |
222 | + lb: TListBox absolute Control; | |
223 | + NoteColor: TDenkzettelColor; | |
224 | + IsChecklist: boolean; | |
225 | + cnv: TCanvas; | |
226 | + s: string; | |
227 | +begin | |
228 | + s := lb.Items[Index]; | |
229 | + PointerToProperties(lb.Items.Objects[Index], NoteColor, IsChecklist); | |
230 | + cnv := lb.Canvas; | |
231 | + | |
232 | + cnv.Brush.Color := NoteColorToColor(NoteColor, odSelected in State); | |
233 | + cnv.FillRect(ARect); | |
234 | + | |
235 | + if odSelected in State then | |
236 | + cnv.TextRect(ARect, arect.Left, arect.Top, '>'); | |
237 | + cnv.TextRect(ARect, ARect.Left + 10, ARect.Top, s); | |
238 | + | |
239 | + // Focus rect is drawn automatically | |
240 | +end; | |
241 | + | |
242 | +end. |
@@ -0,0 +1,227 @@ | ||
1 | +unit u_DenkzettelUtils; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Windows, | |
9 | + SysUtils, | |
10 | + Classes, | |
11 | + Graphics; | |
12 | + | |
13 | +type | |
14 | + TDenkzettelColor = (dcWhite, dcRed, dcOrange, dcYellow, dcMagenta, dcViolet, dcBlue, dcGreen); | |
15 | + | |
16 | + | |
17 | +function DecodeFilename(const _fn: string; | |
18 | + out _Title: string; out _IsChecklist: boolean; out _Color: TDenkzettelColor): boolean; | |
19 | + | |
20 | +function EncodeFilename(const _Title: string; _IsChecklist: boolean; _Color: TDenkzettelColor): string; | |
21 | + | |
22 | +function PropertiesToPointer(_Color: TDenkzettelColor; _IsChecklist: boolean): Pointer; | |
23 | +procedure PointerToProperties(_Ptr: Pointer; out _Color: TDenkzettelColor; out _IsChecklist: boolean); | |
24 | + | |
25 | +function NoteColorToColor(_NoteColor: TDenkzettelColor; _IsSelected: boolean): TColor; | |
26 | +function DarkenColor(_Color: TColor; _Percent: byte): TColor; | |
27 | +function BrightenColor(_Color: TColor; _Percent: byte): TColor; | |
28 | +function NoteColorToChar(_dc: TDenkzettelColor): char; | |
29 | +function CharToNoteColor(_c: char): TDenkzettelColor; | |
30 | + | |
31 | +implementation | |
32 | + | |
33 | +uses | |
34 | + strutils; | |
35 | + | |
36 | +type | |
37 | + TPropEncoderRec = packed record | |
38 | + case boolean of | |
39 | + True: (AsPointer: Pointer); | |
40 | + False: ( | |
41 | + Color: TDenkzettelColor; | |
42 | + IsChecklist: boolean); | |
43 | + end; | |
44 | + | |
45 | +function PropertiesToPointer(_Color: TDenkzettelColor; _IsChecklist: boolean): Pointer; | |
46 | +var | |
47 | + rec: TPropEncoderRec; | |
48 | +begin | |
49 | + ZeroMemory(@rec, SizeOf(rec)); | |
50 | + rec.Color := _Color; | |
51 | + rec.IsChecklist := _IsChecklist; | |
52 | + Result := rec.AsPointer; | |
53 | +end; | |
54 | + | |
55 | +procedure PointerToProperties(_Ptr: Pointer; out _Color: TDenkzettelColor; out _IsChecklist: boolean); | |
56 | +var | |
57 | + rec: TPropEncoderRec; | |
58 | +begin | |
59 | + ZeroMemory(@rec, SizeOf(rec)); | |
60 | + rec.AsPointer := _Ptr; | |
61 | + _Color := rec.Color; | |
62 | + _IsChecklist := rec.IsChecklist; | |
63 | +end; | |
64 | + | |
65 | +function DarkenColor(_Color: TColor; _Percent: byte): TColor; | |
66 | +var R, G, B: byte; | |
67 | +begin | |
68 | + R := GetRValue(_Color); | |
69 | + G := GetGValue(_Color); | |
70 | + B := GetBValue(_Color); | |
71 | + R := Round(R * _Percent / 100); | |
72 | + G := Round(G * _Percent / 100); | |
73 | + B := Round(B * _Percent / 100); | |
74 | + Result := RGB(R, G, B); | |
75 | +end; | |
76 | + | |
77 | +function BrightenColor(_Color: TColor; _Percent: byte): TColor; | |
78 | +var R, G, B: byte; | |
79 | +begin | |
80 | + R := GetRValue(_Color); | |
81 | + G := GetGValue(_Color); | |
82 | + B := GetBValue(_Color); | |
83 | + R := Round(R * _Percent / 100) + Round(255 - _Percent / 100 * 255); | |
84 | + G := Round(G * _Percent / 100) + Round(255 - _Percent / 100 * 255); | |
85 | + B := Round(B * _Percent / 100) + Round(255 - _Percent / 100 * 255); | |
86 | + Result := RGB(R, G, B); | |
87 | +end; | |
88 | + | |
89 | + | |
90 | + | |
91 | +function NoteColorToColor(_NoteColor: TDenkzettelColor; _IsSelected: boolean): TColor; | |
92 | +var | |
93 | + clDenkzettelRed: TColor; | |
94 | + clDenkzettelOrange: TColor; | |
95 | + clDenkzettelYellow: TColor; | |
96 | + clDenkzettelMagenta: TColor; | |
97 | + clDenkzettelViolet: TColor; | |
98 | + clDenkzettelBlue: TColor; | |
99 | + clDenkzettelGreen: TColor; | |
100 | +begin | |
101 | + clDenkzettelRed := RGBToColor(255, 180, 180); //RGBToColor(255, 128, 128); | |
102 | + clDenkzettelOrange := RGBToColor(250, 192, 86); //RGBToColor(255, 170, 130); | |
103 | + clDenkzettelYellow := RGBToColor(255, 255, 128); | |
104 | + clDenkzettelMagenta := RGBToColor(255, 170, 255); | |
105 | + clDenkzettelViolet := RGBToColor(217, 179, 255); | |
106 | + clDenkzettelBlue := RGBToColor(152, 218, 254); | |
107 | + clDenkzettelGreen := RGBToColor(193, 255, 193); | |
108 | + | |
109 | + case _NoteColor of | |
110 | + dcRed: Result := clDenkzettelRed; | |
111 | + dcOrange: Result := clDenkzettelOrange; | |
112 | + dcYellow: Result := clDenkzettelYellow; | |
113 | + dcMagenta: Result := clDenkzettelMagenta; | |
114 | + dcViolet: Result := clDenkzettelViolet; | |
115 | + dcBlue: Result := clDenkzettelBlue; | |
116 | + dcGreen: Result := clDenkzettelGreen; | |
117 | + else // dcWhite: | |
118 | + if _IsSelected then | |
119 | + Result := clHighlight | |
120 | + else | |
121 | + Result := clWindow; | |
122 | + Exit; //==> | |
123 | + end; | |
124 | + if _IsSelected then | |
125 | + Result := DarkenColor(Result, 80); | |
126 | +end; | |
127 | + | |
128 | +function ExtractHashSuffix(var _s: string; out _Suffix: string): boolean; | |
129 | +var | |
130 | + len: integer; | |
131 | + i: integer; | |
132 | +begin | |
133 | + Result := False; | |
134 | + if _s = '' then | |
135 | + Exit; //==> | |
136 | + Len := Length(_s); | |
137 | + if _s[Len] <> '#' then | |
138 | + Exit; //==> | |
139 | + i := Len - 1; | |
140 | + while i > 0 do begin | |
141 | + if _s[i] = '#' then begin | |
142 | + _Suffix := Copy(_s, i); | |
143 | + _s := LeftStr(_s, i - 1); | |
144 | + Result := True; | |
145 | + Exit; //==> | |
146 | + end; | |
147 | + Dec(i); | |
148 | + end; | |
149 | +end; | |
150 | + | |
151 | +function NoteColorToChar(_dc: TDenkzettelColor): char; | |
152 | +begin | |
153 | + case _dc of | |
154 | + dcRed: Result := 'R'; | |
155 | + dcOrange: Result := 'O'; | |
156 | + dcYellow: Result := 'Y'; | |
157 | + dcMagenta: Result := 'M'; | |
158 | + dcViolet: Result := 'V'; | |
159 | + dcBlue: Result := 'B'; | |
160 | + dcGreen: Result := 'G'; | |
161 | + else | |
162 | + Result := 'W'; | |
163 | + end; | |
164 | +end; | |
165 | + | |
166 | +function CharToNoteColor(_c: char): TDenkzettelColor; | |
167 | +begin | |
168 | + case _c of | |
169 | + 'R': Result := dcRed; | |
170 | + 'O': Result := dcOrange; | |
171 | + 'Y': Result := dcYellow; | |
172 | + 'M': Result := dcMagenta; | |
173 | + 'V': Result := dcViolet; | |
174 | + 'B': Result := dcBlue; | |
175 | + 'G': Result := dcGreen; | |
176 | + else | |
177 | + Result := dcWhite; | |
178 | + end; | |
179 | +end; | |
180 | + | |
181 | +function DecodeFilename(const _fn: string; | |
182 | + out _Title: string; out _IsChecklist: boolean; out _Color: TDenkZettelColor): boolean; | |
183 | +var | |
184 | + s: string; | |
185 | + Suffix: string; | |
186 | + Option: string; | |
187 | + Value: string; | |
188 | +begin | |
189 | + s := ChangeFileExt(ExtractFileName(_fn), ''); | |
190 | + Result := False; | |
191 | + _IsChecklist := False; | |
192 | + _Color := dcWhite; | |
193 | + _Title := s; | |
194 | + while ExtractHashSuffix(s, Suffix) do begin | |
195 | + if LeftStr(Suffix, 1) <> '#' then | |
196 | + Exit; //==> | |
197 | + if RightStr(Suffix, 1) <> '#' then | |
198 | + Exit; //==> | |
199 | + Option := Copy(Suffix, 2, Length(Suffix) - 2); | |
200 | + Value := UpCase(Copy(Option, 2)); | |
201 | + Option := UpCase(LeftStr(Option, 1)); | |
202 | + case Option[1] of | |
203 | + 'C': begin | |
204 | + // Color | |
205 | + if Length(Value) <> 1 then | |
206 | + Exit; //==> | |
207 | + _Color := CharToNoteColor(Value[1]); | |
208 | + end; | |
209 | + 'L': begin | |
210 | + _IsChecklist := True; | |
211 | + end; | |
212 | + end; | |
213 | + end; | |
214 | + _Title := s; | |
215 | + Result := True; | |
216 | +end; | |
217 | + | |
218 | +function EncodeFilename(const _Title: string; _IsChecklist: boolean; _Color: TDenkzettelColor): string; | |
219 | +begin | |
220 | + Result := _Title; | |
221 | + if _IsChecklist then | |
222 | + Result := Result + '#L#'; | |
223 | + if _Color <> dcWhite then | |
224 | + Result := Result + '#C' + NoteColorToChar(_Color) + '#'; | |
225 | +end; | |
226 | + | |
227 | +end. |
@@ -0,0 +1,120 @@ | ||
1 | +unit w_SelectColor; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + Graphics, | |
14 | + Dialogs, | |
15 | + ExtCtrls, | |
16 | + u_DenkzettelUtils; | |
17 | + | |
18 | +type | |
19 | + | |
20 | + { Tf_SelectColor } | |
21 | + | |
22 | + Tf_SelectColor = class(TForm) | |
23 | + p_White: TPanel; | |
24 | + procedure FormKeyPress(Sender: TObject; var Key: char); | |
25 | + procedure p_WhiteClick(Sender: TObject); | |
26 | + private | |
27 | + FSelectedColor: TDenkzettelColor; | |
28 | + procedure GetValue(out _Color: TDenkzettelColor); | |
29 | + public | |
30 | + class function Execute(_Owner: TWinControl; var _Color: TDenkzettelColor): boolean; | |
31 | + constructor Create(_Owner: TComponent); override; | |
32 | + end; | |
33 | + | |
34 | +implementation | |
35 | + | |
36 | +{$R *.lfm} | |
37 | + | |
38 | +uses | |
39 | + u_dzLazUtils; | |
40 | + | |
41 | +{ Tf_SelectColor } | |
42 | + | |
43 | +class function Tf_SelectColor.Execute(_Owner: TWinControl; var _Color: TDenkzettelColor): boolean; | |
44 | +var | |
45 | + frm: Tf_SelectColor; | |
46 | +begin | |
47 | + frm := Tf_SelectColor.Create(_Owner); | |
48 | + try | |
49 | + TForm_CenterOn(frm, _Owner); | |
50 | + Result := (frm.ShowModal = mrOk); | |
51 | + if Result then | |
52 | + frm.GetValue(_Color); | |
53 | + finally | |
54 | + FreeAndNil(frm); | |
55 | + end; | |
56 | +end; | |
57 | + | |
58 | +constructor Tf_SelectColor.Create(_Owner: TComponent); | |
59 | +var | |
60 | + dc: TDenkzettelColor; | |
61 | + pnl: TPanel; | |
62 | + h: integer; | |
63 | + t: integer; | |
64 | +begin | |
65 | + inherited Create(_Owner); | |
66 | + p_White.Caption := NoteColorToChar(dcWhite); | |
67 | + p_White.Color := NoteColorToColor(dcWhite, False); | |
68 | + | |
69 | + t := p_White.Top; | |
70 | + h := t + p_White.Height; | |
71 | + for dc := Succ(Low(TDenkzettelColor)) to high(TDenkzettelColor) do begin | |
72 | + t := t + h; | |
73 | + pnl := TPanel.Create(Self); | |
74 | + pnl.Parent := Self; | |
75 | + pnl.Top := t; | |
76 | + pnl.Height := p_White.Height; | |
77 | + pnl.Left := p_White.Left; | |
78 | + pnl.Width := p_White.Width; | |
79 | + pnl.Caption := NoteColorToChar(dc); | |
80 | + pnl.Name := ''; | |
81 | + pnl.Color := NoteColorToColor(dc, False); | |
82 | + pnl.Tag := Ord(dc); | |
83 | + pnl.OnClick := p_White.OnClick; | |
84 | + end; | |
85 | + Self.Height := t; | |
86 | +end; | |
87 | + | |
88 | +procedure Tf_SelectColor.p_WhiteClick(Sender: TObject); | |
89 | +begin | |
90 | + FSelectedColor := TDenkzettelColor((Sender as TPanel).Tag); | |
91 | + ModalResult := mrOk; | |
92 | +end; | |
93 | + | |
94 | +procedure Tf_SelectColor.FormKeyPress(Sender: TObject; var Key: char); | |
95 | +var | |
96 | + ctrl: TControl; | |
97 | + pnl: TPanel; | |
98 | + i: Integer; | |
99 | + c: char; | |
100 | +begin | |
101 | + c := UpCase(Key); | |
102 | + for i := 0 to ControlCount - 1 do begin | |
103 | + ctrl := Controls[i]; | |
104 | + if ctrl is TPanel then begin | |
105 | + pnl := TPanel(ctrl); | |
106 | + if pnl.Caption = c then begin | |
107 | + pnl.OnClick(pnl); | |
108 | + Exit; //==> | |
109 | + end; | |
110 | + end; | |
111 | + end; | |
112 | +end; | |
113 | + | |
114 | +procedure Tf_SelectColor.GetValue(out _Color: TDenkzettelColor); | |
115 | +begin | |
116 | + _Color := FSelectedColor; | |
117 | +end; | |
118 | + | |
119 | + | |
120 | +end. |
@@ -0,0 +1,217 @@ | ||
1 | +unit wf_Categories; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + StdCtrls, | |
14 | + ExtCtrls, | |
15 | + Menus, | |
16 | + wf_Notes, | |
17 | + Types; | |
18 | + | |
19 | +type | |
20 | + | |
21 | + { Tfr_Categories } | |
22 | + | |
23 | + Tfr_Categories = class(TFrame) | |
24 | + b_Menu: TButton; | |
25 | + lb_Categories: TListBox; | |
26 | + mi_About: TMenuItem; | |
27 | + mi_Configure: TMenuItem; | |
28 | + mi_NewCategory: TMenuItem; | |
29 | + pm_Main: TPopupMenu; | |
30 | + P_Categories: TPanel; | |
31 | + p_Main: TPanel; | |
32 | + procedure b_MenuClick(Sender: TObject); | |
33 | + procedure FrameEnter(Sender: TObject); | |
34 | + procedure lb_CategoriesDrawItem(Control: TWinControl; Index: integer; | |
35 | + ARect: TRect; State: TOwnerDrawState); | |
36 | + procedure mi_AboutClick(Sender: TObject); | |
37 | + procedure mi_NewCategoryClick(Sender: TObject); | |
38 | + procedure mi_ConfigureClick(Sender: TObject); | |
39 | + procedure lb_CategoriesDblClick(Sender: TObject); | |
40 | + procedure lb_CategoriesKeyPress(Sender: TObject; var Key: char); | |
41 | + private | |
42 | + FBasePath: ^string; | |
43 | + FNotesFrame: Tfr_Notes; | |
44 | + function BasePathBS: string; | |
45 | + function TryGetCategory(out _Category: string): boolean; | |
46 | + procedure OnCloseCategory(_Sender: TObject); | |
47 | + public | |
48 | + constructor Create(_Owner: TComponent); override; | |
49 | + procedure Init(var _BasePath: string); | |
50 | + procedure GoBack; | |
51 | + procedure OpenSelected; | |
52 | + procedure ShowMenu; | |
53 | + procedure OnCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
54 | + end; | |
55 | + | |
56 | +implementation | |
57 | + | |
58 | +{$R *.lfm} | |
59 | + | |
60 | +uses | |
61 | + Graphics, | |
62 | + LCLType, | |
63 | + u_dzLazUtils, | |
64 | + u_DenkzettelUtils, | |
65 | + w_NewCategory, | |
66 | + w_Settings, | |
67 | + w_About; | |
68 | + | |
69 | +{ Tfr_Categories } | |
70 | + | |
71 | +constructor Tfr_Categories.Create(_Owner: TComponent); | |
72 | +begin | |
73 | + inherited Create(_Owner); | |
74 | + | |
75 | + b_Menu.Caption := TRICOLON; | |
76 | + | |
77 | + FNotesFrame := Tfr_Notes.Create(Self); | |
78 | + FNotesFrame.Visible := False; | |
79 | + FNotesFrame.Parent := Self; | |
80 | + FNotesFrame.Align := alClient; | |
81 | + FNotesFrame.OnClose := @OnCloseCategory; | |
82 | +end; | |
83 | + | |
84 | +procedure Tfr_Categories.Init(var _BasePath: string); | |
85 | +begin | |
86 | + FBasePath := @_BasePath; | |
87 | + | |
88 | + EnumDirectories(BasePathBS, lb_Categories.Items, True, False); | |
89 | + TWinControl_SetFocus(lb_Categories); | |
90 | +end; | |
91 | + | |
92 | +procedure Tfr_Categories.OnCloseQuery(_Sender: TObject; var _CanClose: boolean); | |
93 | +begin | |
94 | + if not FNotesFrame.Visible then | |
95 | + Exit; //==> | |
96 | + FNotesFrame.FormCloseQuery(_Sender, _CanClose); | |
97 | +end; | |
98 | + | |
99 | +procedure Tfr_Categories.OpenSelected; | |
100 | +var | |
101 | + Category: string; | |
102 | +begin | |
103 | + if not Assigned(FNotesFrame) then | |
104 | + Exit; //==> | |
105 | + if FNotesFrame.Visible then | |
106 | + FNotesFrame.OpenSelected | |
107 | + else begin | |
108 | + if not TryGetCategory(Category) then | |
109 | + Exit; //==> | |
110 | + FNotesFrame.Init(Category, BasePathBS + Category); | |
111 | + FNotesFrame.Visible := True; | |
112 | + p_Main.Visible := False; | |
113 | + end; | |
114 | +end; | |
115 | + | |
116 | +procedure Tfr_Categories.lb_CategoriesDblClick(Sender: TObject); | |
117 | +begin | |
118 | + OpenSelected; | |
119 | +end; | |
120 | + | |
121 | +procedure Tfr_Categories.lb_CategoriesKeyPress(Sender: TObject; var Key: char); | |
122 | +begin | |
123 | + if Key in [#13, #10] then | |
124 | + OpenSelected; | |
125 | +end; | |
126 | + | |
127 | +procedure Tfr_Categories.mi_AboutClick(Sender: TObject); | |
128 | +begin | |
129 | + Tf_About.Execute(Self); | |
130 | +end; | |
131 | + | |
132 | +procedure Tfr_Categories.GoBack; | |
133 | +begin | |
134 | + if Assigned(FNotesFrame) and FNotesFrame.Visible then | |
135 | + FNotesFrame.GoBack; | |
136 | +end; | |
137 | + | |
138 | +procedure Tfr_Categories.ShowMenu; | |
139 | +begin | |
140 | + if Assigned(FNotesFrame) and FNotesFrame.Visible then | |
141 | + FNotesFrame.ShowMenu | |
142 | + else begin | |
143 | + TButton_DrowpdownMenu(b_Menu, pm_Main); | |
144 | + end; | |
145 | +end; | |
146 | + | |
147 | +procedure Tfr_Categories.b_MenuClick(Sender: TObject); | |
148 | +begin | |
149 | + ShowMenu; | |
150 | +end; | |
151 | + | |
152 | +procedure Tfr_Categories.FrameEnter(Sender: TObject); | |
153 | +begin | |
154 | + TWinControl_SetFocus(lb_Categories); | |
155 | + if lb_Categories.ItemIndex = -1 then | |
156 | + if lb_Categories.Items.Count > 0 then | |
157 | + lb_Categories.ItemIndex := 0; | |
158 | +end; | |
159 | + | |
160 | +procedure Tfr_Categories.lb_CategoriesDrawItem(Control: TWinControl; | |
161 | + Index: integer; ARect: TRect; State: TOwnerDrawState); | |
162 | +var | |
163 | + lb: TListBox absolute Control; | |
164 | + cnv: TCanvas; | |
165 | + s: string; | |
166 | +begin | |
167 | + s := lb.Items[Index]; | |
168 | + cnv := lb.Canvas; | |
169 | + | |
170 | + cnv.Brush.Color := NoteColorToColor(dcWhite, (odSelected in State)); | |
171 | + cnv.FillRect(ARect); | |
172 | + if odSelected in State then | |
173 | + cnv.TextRect(ARect, arect.Left, arect.Top, '>'); | |
174 | + cnv.TextRect(ARect, ARect.Left + 10, ARect.Top, s); | |
175 | + | |
176 | + // Focus rect is drawn automatically | |
177 | +end; | |
178 | + | |
179 | +procedure Tfr_Categories.mi_NewCategoryClick(Sender: TObject); | |
180 | +var | |
181 | + NewCategory: string; | |
182 | +begin | |
183 | + if Tf_NewCategory.Execute(Self, BasePathBS, NewCategory) then | |
184 | + Init(FBasePath^); | |
185 | +end; | |
186 | + | |
187 | +procedure Tfr_Categories.mi_ConfigureClick(Sender: TObject); | |
188 | +begin | |
189 | + if Tf_Settings.Execute(self, FBasePath^) then | |
190 | + Init(FBasePath^); | |
191 | +end; | |
192 | + | |
193 | +function Tfr_Categories.BasePathBS: string; | |
194 | +begin | |
195 | + Result := IncludeTrailingPathDelimiter(FBasePath^); | |
196 | +end; | |
197 | + | |
198 | +function Tfr_Categories.TryGetCategory(out _Category: string): boolean; | |
199 | +var | |
200 | + Idx: integer; | |
201 | +begin | |
202 | + Result := False; | |
203 | + Idx := lb_Categories.ItemIndex; | |
204 | + if Idx = -1 then | |
205 | + Exit; //==> | |
206 | + _Category := lb_Categories.Items[Idx]; | |
207 | + Result := (_Category <> ''); | |
208 | +end; | |
209 | + | |
210 | +procedure Tfr_Categories.OnCloseCategory(_Sender: TObject); | |
211 | +begin | |
212 | + FNotesFrame.Visible := False; | |
213 | + p_Main.Visible := True; | |
214 | + TWinControl_SetFocus(lb_Categories); | |
215 | +end; | |
216 | + | |
217 | +end. |
@@ -0,0 +1,183 @@ | ||
1 | +unit u_dzLazUtils; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + SysUtils, | |
9 | + Types, | |
10 | + Classes, | |
11 | + Controls, | |
12 | + StdCtrls, | |
13 | + Menus, | |
14 | + Forms; | |
15 | + | |
16 | +const | |
17 | + TRICOLON = #$E2#$81#$9D; // UTF-8 for #$205D tricolon unicode character | |
18 | + | |
19 | +procedure EnumDirectories(const _Base: string; _Dirs: TStrings; | |
20 | + _Sorted: boolean = True; _FullName: boolean = True; const _Mask: string = '*'); | |
21 | +procedure EnumFiles(const _Base: string; const _Mask: string; _Files: TStrings; _Sorted: boolean = True; | |
22 | + _FullName: boolean = True; _AdditionalAttribs: integer = 0); overload; | |
23 | +procedure EnumFiles(const _FullMask: string; _Files: TStrings; _Sorted: boolean = True; | |
24 | + _FullName: boolean = True; _AdditionalAttribs: integer = 0); overload; | |
25 | +///<summary> | |
26 | +/// Find a file matching the mask and return its name. If there are more than one matches, return | |
27 | +/// the first. | |
28 | +/// @param Mask is the mask the filen name must match | |
29 | +/// @param fn is the first file that was found, if any. Only valid if Result >0 | |
30 | +/// @returns the number of matching files found. </summary> | |
31 | +function FindMatchingFile(const _Mask: string; out _fn: string): integer; | |
32 | + | |
33 | +procedure TForm_CenterOn(_frm: TForm; _Owner: TWinControl); overload; | |
34 | +function TForm_GetCenter(_frm: TForm): TPoint; | |
35 | + | |
36 | +function TControl_GetParentFormCenter(_ctrl: TControl): TPoint; | |
37 | + | |
38 | +procedure TWinControl_SetFocus(_ctrl: TWinControl); | |
39 | + | |
40 | +function TApplication_GetDefaultIniFile: string; | |
41 | +function TApplication_GetExeDir: string; | |
42 | +function TApplication_GetExeDirBS: string; | |
43 | + | |
44 | +procedure TButton_DrowpdownMenu(_btn: TButton; _pm: TPopupMenu); | |
45 | + | |
46 | + | |
47 | +implementation | |
48 | + | |
49 | +function TApplication_GetDefaultIniFile: string; | |
50 | +begin | |
51 | + Result := ChangeFileExt(Application.ExeName, '.ini'); | |
52 | +end; | |
53 | + | |
54 | +function TApplication_GetExeDir: string; | |
55 | +begin | |
56 | + Result := ExtractFileDir(Application.ExeName); | |
57 | +end; | |
58 | + | |
59 | +function TApplication_GetExeDirBS: string; | |
60 | +begin | |
61 | + Result := IncludeTrailingPathDelimiter(TApplication_GetExeDir); | |
62 | +end; | |
63 | + | |
64 | +procedure EnumDirectories(const _Base: string; _Dirs: TStrings; | |
65 | + _Sorted: boolean = True; _FullName: boolean = True; const _Mask: string = '*'); | |
66 | +var | |
67 | + Base: string; | |
68 | + SearchRec: TRawByteSearchRec; | |
69 | + Dirs: TStringList; | |
70 | +begin | |
71 | + _Dirs.Clear; | |
72 | + Base := IncludeTrailingPathDelimiter(_Base); | |
73 | + if FindFirst(Base + _Mask, faDirectory, SearchRec) = 0 then begin | |
74 | + Dirs := TStringList.Create; | |
75 | + try | |
76 | + if not _FullName then | |
77 | + base := ''; | |
78 | + repeat | |
79 | + if (SearchRec.Attr and faDirectory) <> 0 then | |
80 | + if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin | |
81 | + Dirs.Add(Base + SearchRec.Name); | |
82 | + end; | |
83 | + until FindNext(SearchRec) <> 0; | |
84 | + if _Sorted then | |
85 | + Dirs.Sort; | |
86 | + _Dirs.Assign(Dirs); | |
87 | + finally | |
88 | + FindClose(SearchRec); | |
89 | + end; | |
90 | + end; | |
91 | +end; | |
92 | + | |
93 | +procedure EnumFiles(const _Base: string; const _Mask: string; _Files: TStrings; _Sorted: boolean = True; | |
94 | + _FullName: boolean = True; _AdditionalAttribs: integer = 0); | |
95 | +begin | |
96 | + EnumFiles(IncludeTrailingPathDelimiter(_Base) + _Mask, _Files, _Sorted, _FullName, _AdditionalAttribs); | |
97 | +end; | |
98 | + | |
99 | +procedure EnumFiles(const _FullMask: string; _Files: TStrings; _Sorted: boolean = True; | |
100 | + _FullName: boolean = True; _AdditionalAttribs: integer = 0); | |
101 | +var | |
102 | + SearchRec: TRawbyteSearchRec; | |
103 | + Files: TStringList; | |
104 | + Base: string; | |
105 | +begin | |
106 | + _Files.Clear; | |
107 | + if FindFirst(_FullMask, faArchive + _AdditionalAttribs, SearchRec) = 0 then begin | |
108 | + Files := TStringList.Create; | |
109 | + try | |
110 | + if _FullName then begin | |
111 | + Base := ExtractFileDir(_FullMask); | |
112 | + Base := IncludeTrailingPathDelimiter(Base); | |
113 | + end else | |
114 | + base := ''; | |
115 | + repeat | |
116 | + if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin | |
117 | + Files.Add(Base + SearchRec.Name); | |
118 | + end; | |
119 | + until FindNext(SearchRec) <> 0; | |
120 | + if _Sorted then | |
121 | + Files.Sort; | |
122 | + _Files.Assign(Files); | |
123 | + finally | |
124 | + FindClose(SearchRec); | |
125 | + end; | |
126 | + end; | |
127 | +end; | |
128 | + | |
129 | +function FindMatchingFile(const _Mask: string; out _fn: string): integer; | |
130 | +var | |
131 | + Files: TStringList; | |
132 | +begin | |
133 | + Files := TStringList.Create; | |
134 | + try | |
135 | + EnumFiles(_Mask, Files); | |
136 | + Result := Files.Count; | |
137 | + if Result > 0 then | |
138 | + _fn := Files[0]; | |
139 | + finally | |
140 | + FreeAndNil(Files); | |
141 | + end; | |
142 | +end; | |
143 | + | |
144 | +procedure TForm_CenterOn(_frm: TForm; _Owner: TWinControl); | |
145 | +var | |
146 | + Center: TPoint; | |
147 | +begin | |
148 | + Center := _Owner.ClientToScreen(Point(_Owner.Width div 2, _Owner.Height div 2)); | |
149 | + _frm.Left := Center.X - _frm.Width div 2; | |
150 | + _frm.Top := Center.Y - _frm.Height div 2; | |
151 | +end; | |
152 | + | |
153 | +function TForm_GetCenter(_frm: TForm): TPoint; | |
154 | +begin | |
155 | + Result := _frm.ClientToScreen(Point(_frm.Width div 2, _frm.Height div 2)); | |
156 | +end; | |
157 | + | |
158 | +function TControl_GetParentFormCenter(_ctrl: TControl): TPoint; | |
159 | +begin | |
160 | + Result := _ctrl.ClientToScreen(Point(_ctrl.Width div 2, _ctrl.Height div 2)); | |
161 | +end; | |
162 | + | |
163 | +procedure TWinControl_SetFocus(_ctrl: TWinControl); | |
164 | +begin | |
165 | + try | |
166 | + if _ctrl.CanSetFocus then | |
167 | + _ctrl.SetFocus | |
168 | + except | |
169 | + on e: EInvalidOperation do | |
170 | + ; // ignore | |
171 | + end; | |
172 | +end; | |
173 | + | |
174 | +procedure TButton_DrowpdownMenu(_btn: TButton; _pm: TPopupMenu); | |
175 | +var | |
176 | + pnt: Types.TPoint; | |
177 | +begin | |
178 | + pnt := _btn.ClientToScreen(Point(0, _btn.Height)); | |
179 | + _pm.PopUp(pnt.x, pnt.y); | |
180 | +end; | |
181 | + | |
182 | +end. | |
183 | + |
@@ -0,0 +1,103 @@ | ||
1 | +unit w_DenkzettelCompanion; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Windows, | |
9 | + Classes, | |
10 | + SysUtils, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + Menus, | |
14 | + wf_Categories; | |
15 | + | |
16 | +type | |
17 | + | |
18 | + { Tf_DenkzettelCompanion } | |
19 | + | |
20 | + Tf_DenkzettelCompanion = class(TForm) | |
21 | + procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); | |
22 | + procedure FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState); | |
23 | + private | |
24 | + FBasePath: string; | |
25 | + FCategoriesFrame: Tfr_Categories; | |
26 | + public | |
27 | + constructor Create(_Owner: TComponent); override; | |
28 | + destructor Destroy; override; | |
29 | + end; | |
30 | + | |
31 | +var | |
32 | + f_DenkzettelCompanion: Tf_DenkzettelCompanion; | |
33 | + | |
34 | +implementation | |
35 | + | |
36 | +{$R *.lfm} | |
37 | + | |
38 | +uses | |
39 | + IniFiles, | |
40 | + u_dzLazUtils; | |
41 | + | |
42 | +{ Tf_DenkzettelCompanion } | |
43 | + | |
44 | +constructor Tf_DenkzettelCompanion.Create(_Owner: TComponent); | |
45 | +var | |
46 | + Ini: TIniFile; | |
47 | +begin | |
48 | + inherited Create(_Owner); | |
49 | + | |
50 | + Ini := TIniFile.Create(TApplication_GetDefaultIniFile); | |
51 | + try | |
52 | + FBasePath := Ini.ReadString('common', 'BasePath', TApplication_GetExeDirBS + 'Notes'); | |
53 | + finally | |
54 | + FreeAndNil(Ini); | |
55 | + end; | |
56 | + | |
57 | + FCategoriesFrame := Tfr_Categories.Create(Self); | |
58 | + FCategoriesFrame.Parent := Self; | |
59 | + FCategoriesFrame.Align := alClient; | |
60 | + FCategoriesFrame.Init(FBasePath); | |
61 | +end; | |
62 | + | |
63 | +destructor Tf_DenkzettelCompanion.Destroy; | |
64 | +var | |
65 | + Ini: TIniFile; | |
66 | +begin | |
67 | + try | |
68 | + Ini := TIniFile.Create(TApplication_GetDefaultIniFile); | |
69 | + try | |
70 | + Ini.WriteString('common', 'BasePath', FBasePath); | |
71 | + finally | |
72 | + FreeAndNil(Ini); | |
73 | + end; | |
74 | + except | |
75 | + // ignore exceptions in destructor | |
76 | + end; | |
77 | + inherited Destroy; | |
78 | +end; | |
79 | + | |
80 | +procedure Tf_DenkzettelCompanion.FormCloseQuery(Sender: TObject; var CanClose: boolean); | |
81 | +begin | |
82 | + FCategoriesFrame.OnCloseQuery(Sender, CanClose); | |
83 | +end; | |
84 | + | |
85 | +procedure Tf_DenkzettelCompanion.FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState); | |
86 | +begin | |
87 | + if not Assigned(FCategoriesFrame) then | |
88 | + Exit; //==> | |
89 | + if Key = VK_F10 then begin | |
90 | + if shift = [] then begin | |
91 | + FCategoriesFrame.ShowMenu; | |
92 | + Key := 0; | |
93 | + end; | |
94 | + end else if Key = VK_LEFT then begin | |
95 | + if shift = [ssAlt] then | |
96 | + FCategoriesFrame.GoBack; | |
97 | + end else if Key = VK_RIGHT then begin | |
98 | + if shift = [ssAlt] then | |
99 | + FCategoriesFrame.OpenSelected; | |
100 | + end; | |
101 | +end; | |
102 | + | |
103 | +end. |
@@ -0,0 +1,58 @@ | ||
1 | +unit w_About; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + Graphics, | |
14 | + Dialogs, ExtCtrls, StdCtrls; | |
15 | + | |
16 | +type | |
17 | + | |
18 | + { Tf_About } | |
19 | + | |
20 | + Tf_About = class(TForm) | |
21 | + b_Close: TButton; | |
22 | + im_Logo: TImage; | |
23 | + l_ProgInfo1: TLabel; | |
24 | + l_ProgInfo2: TLabel; | |
25 | + l_ProgInfo3: TLabel; | |
26 | + l_ProgInfo5: TLabel; | |
27 | + l_ProgName: TLabel; | |
28 | + l_Copyright: TLabel; | |
29 | + l_ProgInfo4: TLabel; | |
30 | + private | |
31 | + public | |
32 | + class procedure Execute(_Owner: TWinControl); | |
33 | + end; | |
34 | + | |
35 | + | |
36 | +implementation | |
37 | + | |
38 | +{$R *.lfm} | |
39 | + | |
40 | +uses | |
41 | + u_dzLazUtils; | |
42 | + | |
43 | +{ Tf_About } | |
44 | + | |
45 | +class procedure Tf_About.Execute(_Owner: TWinControl); | |
46 | +var | |
47 | + frm: Tf_About; | |
48 | +begin | |
49 | + frm := Tf_About.Create(_Owner); | |
50 | + try | |
51 | + TForm_CenterOn(frm, _Owner); | |
52 | + frm.ShowModal; | |
53 | + finally | |
54 | + FreeAndNil(frm); | |
55 | + end; | |
56 | +end; | |
57 | + | |
58 | +end. |
@@ -0,0 +1,84 @@ | ||
1 | +unit w_NewCategory; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + Graphics, | |
14 | + Dialogs, | |
15 | + StdCtrls; | |
16 | + | |
17 | +type | |
18 | + | |
19 | + { Tf_NewCategory } | |
20 | + | |
21 | + Tf_NewCategory = class(TForm) | |
22 | + b_Cancel: TButton; | |
23 | + b_Create: TButton; | |
24 | + ed_Category: TEdit; | |
25 | + l_Blurb: TLabel; | |
26 | + l_Category: TLabel; | |
27 | + procedure b_CreateClick(Sender: TObject); | |
28 | + private | |
29 | + FBaseDir: string; | |
30 | + procedure SetData(const _BaseDir: string; const _CategoryName: string); | |
31 | + procedure GetData(out _CategoryName: string); | |
32 | + public | |
33 | + class function Execute(_Owner: TWinControl; const _BaseDir: string; var _CategoryName: string): boolean; | |
34 | + end; | |
35 | + | |
36 | +implementation | |
37 | + | |
38 | +uses | |
39 | + u_dzLazUtils; | |
40 | + | |
41 | +{$R *.lfm} | |
42 | + | |
43 | +{ Tf_NewCategory } | |
44 | + | |
45 | +class function Tf_NewCategory.Execute(_Owner: TWinControl; const _BaseDir: string; | |
46 | + var _CategoryName: string): boolean; | |
47 | +var | |
48 | + frm: Tf_NewCategory; | |
49 | +begin | |
50 | + frm := Tf_NewCategory.Create(_Owner); | |
51 | + try | |
52 | + TForm_CenterOn(frm, _Owner); | |
53 | + frm.SetData(_BaseDir, _CategoryName); | |
54 | + Result := (mrOk = frm.ShowModal); | |
55 | + if Result then | |
56 | + frm.GetData(_CategoryName); | |
57 | + | |
58 | + finally | |
59 | + FreeAndNil(frm); | |
60 | + end; | |
61 | +end; | |
62 | + | |
63 | +procedure Tf_NewCategory.b_CreateClick(Sender: TObject); | |
64 | +var | |
65 | + NewDir: string; | |
66 | +begin | |
67 | + NewDir := FBaseDir + ed_Category.Text; | |
68 | + if not CreateDir(newdir) then | |
69 | + raise Exception.Create('Could not create directory.'); | |
70 | + ModalResult := mrOk; | |
71 | +end; | |
72 | + | |
73 | +procedure Tf_NewCategory.SetData(const _BaseDir: string; const _CategoryName: string); | |
74 | +begin | |
75 | + FBaseDir := IncludeTrailingPathDelimiter(_BaseDir); | |
76 | + ed_Category.Text := _CategoryName; | |
77 | +end; | |
78 | + | |
79 | +procedure Tf_NewCategory.GetData(out _CategoryName: string); | |
80 | +begin | |
81 | + _CategoryName := ed_Category.Text; | |
82 | +end; | |
83 | + | |
84 | +end. |
@@ -0,0 +1,70 @@ | ||
1 | +unit w_Settings; | |
2 | + | |
3 | +{$mode objfpc}{$H+} | |
4 | + | |
5 | +interface | |
6 | + | |
7 | +uses | |
8 | + Classes, | |
9 | + SysUtils, | |
10 | + FileUtil, | |
11 | + Forms, | |
12 | + Controls, | |
13 | + Graphics, | |
14 | + Dialogs, | |
15 | + StdCtrls, | |
16 | + EditBtn; | |
17 | + | |
18 | +type | |
19 | + | |
20 | + { Tf_Settings } | |
21 | + | |
22 | + Tf_Settings = class(TForm) | |
23 | + b_OK: TButton; | |
24 | + b_Cancel: TButton; | |
25 | + de_BaseDirectory: TDirectoryEdit; | |
26 | + l_BaseDirectory: TLabel; | |
27 | + private | |
28 | + procedure SetData(const _BaseDir: string); | |
29 | + procedure GetData(out _BaseDir: string); | |
30 | + public | |
31 | + class function Execute(_Owner: TWinControl; var _BaseDir: string): boolean; | |
32 | + end; | |
33 | + | |
34 | + | |
35 | +implementation | |
36 | + | |
37 | +{$R *.lfm} | |
38 | + | |
39 | +uses | |
40 | + u_dzLazUtils; | |
41 | + | |
42 | +{ Tf_Settings } | |
43 | + | |
44 | +class function Tf_Settings.Execute(_Owner: TWinControl; var _BaseDir: string): boolean; | |
45 | +var | |
46 | + frm: Tf_Settings; | |
47 | +begin | |
48 | + frm := Tf_Settings.Create(_Owner); | |
49 | + try | |
50 | + TForm_CenterOn(frm, _Owner); | |
51 | + frm.SetData(_BaseDir); | |
52 | + Result := frm.ShowModal = mrOk; | |
53 | + if Result then | |
54 | + frm.GetData(_BaseDir); | |
55 | + finally | |
56 | + FreeAndNil(frm); | |
57 | + end; | |
58 | +end; | |
59 | + | |
60 | +procedure Tf_Settings.SetData(const _BaseDir: string); | |
61 | +begin | |
62 | + de_BaseDirectory.Directory := _BaseDir; | |
63 | +end; | |
64 | + | |
65 | +procedure Tf_Settings.GetData(out _BaseDir: string); | |
66 | +begin | |
67 | + _BaseDir := de_BaseDirectory.Directory; | |
68 | +end; | |
69 | + | |
70 | +end. |
@@ -0,0 +1,15 @@ | ||
1 | +Suffixes for the file name are apparently used to encode the way how Denkzettel displays the | |
2 | +notes: | |
3 | +* #C?# is the background color, where ? is one of: | |
4 | + + R -> Red | |
5 | + + O -> Orange | |
6 | + + Y -> Yellow | |
7 | + + M -> Magenta | |
8 | + + V -> Violet | |
9 | + + B -> Blue | |
10 | + + G -> Green | |
11 | + If there is no #C?# suffix the background color is white | |
12 | + | |
13 | +* #L# means that the note is a checklist | |
14 | + | |
15 | +* Sometimes there is a #N?# suffix (I have only seen #N1# yet, so maybe that's the only value) | |
\ No newline at end of file |