forked from PlummersSoftwareLLC/TinyRetroPad
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdte.asm
More file actions
2276 lines (2015 loc) · 58.1 KB
/
Copy pathdte.asm
File metadata and controls
2276 lines (2015 loc) · 58.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; ---------------------------------------------------------
; _____ _ _____ _
; | __ \ | | | __ \ | |
; | |__) |___| |_ _ __ ___ | |__) |_ _ __| |
; | _ // _ \ __| '__/ _ \| ___/ _` |/ _` |
; | | \ \ __/ |_| | | (_) | | | (_| | (_| |
; |_| \_\___|\__|_| \___/|_| \__,_|\__,_|
; T I N Y X 86 D E S K T O P E D I T O R
; ---------------------------------------------------------
; (c) 2026 Plummer's Software, Ltd.
; Based on Dave's Tiny Editor 2.0.9
; which was
; Based on Dave Plummer's Tiny App
; ---------------------------------------------------------
; Dave's Tiny Editor (DTE)
; Copyright (c) 2026 Matthew M. Power
; Licensed under the Apache License, Version 2.0.
; See LICENSE and NOTICE files in this repository.
; ---------------------------------------------------------
;
; Growth History:
; Added FILE Menus - 1375 Bytes
; Added EDIT Menus - 1428 Bytes
; Expanded FILE Menus (Open/Save As) - 1517 Bytes
; Added HELP Menus - 1557 Bytes
; Added FILE Save Prompt Flow - 1622 Bytes
; Added EDIT Time/Date - 1668 Bytes
; Added FORMAT Word Wrap - 1694 Bytes
; Added Right-Click Context Menu - 1779 Bytes
; Added FORMAT Font Dialog - 1910 Bytes
; Added EDIT Find/FindNext/Replace - 2143 Bytes
; Added FILE Print - 2476 Bytes
; Added VIEW Status Bar (Ln/Col) - 2476 Bytes
; Added DIALOG based Feature - 2686 Bytes
;
; Compiler directives and includes:
.386 ; Full 80386 instruction set and mode
.model flat, stdcall ; All 32-bit and later apps are flat. Used to include "tiny, etc"
option casemap:none ; Preserve the case of system identifiers but not our own, more or less
; Include files - headers and libs that we need for
; calling the system dlls like user32, kernel32, etc
include windows.inc ; Main windows header file (akin to Windows.h in C)
include user32.inc ; Windows, controls, etc
include kernel32.inc ; Handles, modules, paths, etc
;include gdi32.inc ; Removed because no GDI used for editor
; Rich Edit font is set without GDI
; using EM_SETCHARFORMAT
WindowWidth equ 800 ; window startup size
WindowHeight equ 640
IDC_EDIT equ 1001 ; good ole EDIT control from WinAPI
EM_EXLIMITTEXT equ WM_USER+53 ; Rich Edit: raise user editing text limit
EM_SETCHARFORMAT equ WM_USER+68 ; Rich Edit: set text format
EM_SETEVENTMASK equ WM_USER+69 ; Rich Edit: choose which notifications parent gets
EM_SETTARGETDEVICE equ WM_USER+72 ; Rich Edit: wrapping target width
SCF_ALL equ 00000004h ; Rich Edit: apply format to all text
ENM_CHANGE equ 00000001h ; Rich Edit: send EN_CHANGE notifications
CFM_FACE equ 20000000h ; Rich Edit: use font face name
MAX_CMD_PATH equ 128 ; holds startup file path from dropped file
MAX_TITLE equ 128 ; holds window title text (file name and if dirty * )
IDM_SAVE equ 0E100h ; Save menu ID (WM_SYSCOMMAND)
IDM_FILE_NEW equ 0E200h
IDM_FILE_EXIT equ 0E201h
IDM_FILE_OPEN equ 0E202h
IDM_FILE_SAVEAS equ 0E203h
IDM_FILE_PRINT equ 0E204h
IDM_FILE_PAGESETUP equ 0E205h
IDM_EDIT_UNDO equ 0E210h
IDM_EDIT_CUT equ 0E211h
IDM_EDIT_COPY equ 0E212h
IDM_EDIT_PASTE equ 0E213h
IDM_EDIT_DELETE equ 0E214h
IDM_EDIT_SELALL equ 0E215h
IDM_EDIT_TIME equ 0E216h
IDM_EDIT_FIND equ 0E217h
IDM_EDIT_FINDNEXT equ 0E218h
IDM_EDIT_REPLACE equ 0E219h
IDM_EDIT_GOTO equ 0E21Ah
IDM_FMT_WRAP equ 0E220h
IDM_FMT_FONT equ 0E221h
IDM_VIEW_STATUS equ 0E230h
IDM_HELP_ABOUT equ 0E240h
IDM_HELP_VIEWHELP equ 0E241h
IDC_GOEDIT equ 1000 ; Go To dialog edit field id
EM_FORMATRANGE equ WM_USER+57 ; Rich Edit: render text to a DC (printing)
SBHEIGHT equ 20 ; status bar height in pixels
.DATA
EXTERN _imp__CreateWindowExA@48 :PTR ; create main window / EDIT control
EXTERN _imp__GetModuleHandleA@4 :PTR ; get HINSTANCE
EXTERN _imp__LoadLibraryA@4 :PTR ; load modern Rich Edit DLL
EXTERN _imp__RegisterClassA@4 :PTR ; rgstr wndw class (was RegisterClassExA@4)
EXTERN _imp__GetMessageA@16 :PTR ; message loop get
EXTERN _imp__TranslateMessage@4 :PTR ; translate keys
EXTERN _imp__DispatchMessageA@4 :PTR ; dispatch to WndProc
EXTERN _imp__PostQuitMessage@4 :PTR ; exit message loop
EXTERN _imp__DefWindowProcA@16 :PTR ; default window handling
EXTERN _imp__SetWindowPos@28 :PTR ; resize EDIT control
EXTERN _imp__GetCommandLineA@0 :PTR ; get startup file path
EXTERN _imp__CreateFileA@28 :PTR ; open file (read/write)
EXTERN _imp__GetFileSize@8 :PTR ; get file size
EXTERN _imp__GlobalAlloc@8 :PTR ; allocate buffer
EXTERN _imp__GlobalFree@4 :PTR ; free buffer
EXTERN _imp__ReadFile@20 :PTR ; read file into EDIT
EXTERN _imp__WriteFile@20 :PTR ; save EDIT to file
EXTERN _imp__CloseHandle@4 :PTR ; close file handle
EXTERN _imp__SetWindowTextA@8 :PTR ; set title / EDIT text
EXTERN _imp__GetSystemMenu@8 :PTR ; get system menu
EXTERN _imp__AppendMenuA@16 :PTR ; add Save menu item
EXTERN _imp__CreateMenu@0 :PTR ; create main menu bar
EXTERN _imp__CreatePopupMenu@0 :PTR ; create each drop-down menu
EXTERN _imp__SetMenu@8 :PTR ; attach menu bar to main window
EXTERN _imp__DestroyWindow@4 :PTR ; close main window
EXTERN _imp__GetOpenFileNameA@4 :PTR ; common file open dialog
EXTERN _imp__GetSaveFileNameA@4 :PTR ; common file save dialog
EXTERN _imp__GetLocalTime@4 :PTR ; current local time
EXTERN _imp__GetDateFormatA@24 :PTR ; date formatting
EXTERN _imp__GetTimeFormatA@24 :PTR ; time formatting
EXTERN _imp__MessageBoxA@16 :PTR ; simple About dialog
EXTERN _imp__TrackPopupMenu@28 :PTR ; show context popup menu
EXTERN _imp__DestroyMenu@4 :PTR ; free a menu handle
EXTERN _imp__GetMessagePos@0 :PTR ; screen coords of last msg
EXTERN _imp__SendMessageA@16 :PTR ; talk to EDIT control
EXTERN _imp__ChooseFontW@4 :PTR ; common font picker dialog
EXTERN _imp__FindTextA@4 :PTR ; common Find dialog
EXTERN _imp__ReplaceTextA@4 :PTR ; common Replace dialog
EXTERN _imp__RegisterWindowMessageA@4 :PTR ; FINDMSGSTRING message id
EXTERN _imp__IsDialogMessageA@8 :PTR ; route keys to find dialog
EXTERN _imp__PrintDlgA@4 :PTR ; common Print dialog (returns DC)
EXTERN _imp__StartDocA@8 :PTR ; begin print job
EXTERN _imp__StartPage@4 :PTR ; begin a printed page
EXTERN _imp__EndPage@4 :PTR ; finish a printed page
EXTERN _imp__EndDoc@4 :PTR ; finish print job
EXTERN _imp__GetDeviceCaps@8 :PTR ; printer resolution/size
EXTERN _imp__DeleteDC@4 :PTR ; release printer DC
EXTERN _imp__ShowWindow@8 :PTR ; show/hide status bar
EXTERN _imp__GetClientRect@8 :PTR ; client size for relayout
EXTERN _imp__wsprintfA :PTR ; format Ln/Col string
EXTERN _imp__ShellExecuteA@24 :PTR ; open help URL in browser
EXTERN _imp__PageSetupDlgA@4 :PTR ; common Page Setup dialog
EXTERN _imp__DialogBoxIndirectParamA@20 :PTR ; in-memory Go To dialog
EXTERN _imp__GetDlgItemInt@16 :PTR ; read Go To line number
EXTERN _imp__EndDialog@8 :PTR ; close Go To dialog
EXTERN _imp__SetFocus@4 :PTR ; focus edit control after commands
EXTERN _imp__ExitProcess@4 :PTR ; terminate process cleanly
ClassName db ".",0 ; save bytes here (seems to work)
RichDll db "Msftedit",0 ; Rich Edit DLL (no ext saves those bytes)
EditClass db "RICHEDIT50W",0 ; modern Rich Edit control from WinAPI
SaveText db "Save",0 ; button added to system menu
EmptyText db 0
hMain dd 0 ; main window handle
hEdit dd 0 ; EDIT control handle
CmdFile db MAX_CMD_PATH dup (0) ; startup file path buffer
TitleBuf db MAX_TITLE dup (0) ; window title buffer
BytesRead dd 0 ; bytes read from file
fDirty dd 0 ; EDIT modified flag
fWrap dd 1 ; word wrap state
UntitledText db "Untitled",0
NotepadTail db " - RetroPad",0
MFile db "&File",0
MEdit db "&Edit",0
MFormat db "F&ormat",0
MView db "&View",0
MHelp db "&Help",0
MNew db "&New",0
MOpen db "&Open...",0
MSaveMenu db "&Save",0
MSaveAs db "Save &As...",0
MPageSetup db "Page Set&up...",0
MPrint db "&Print...",0
MExit db "E&xit",0
MUndo db "&Undo",0
MCut db "Cu&t",0
MCopy db "&Copy",0
MPaste db "&Paste",0
MDelete db "De&lete",0
MFind db "&Find...",0
MFindNext db "Find &Next",0
MReplace db "&Replace...",0
MGoTo db "&Go To...",0
MSelectAll db "Select &All",0
MTimeDate db "Time/&Date",0
MWordWrap db "&Word Wrap",0
MFont db "&Font...",0
MStatusBar db "&Status Bar",0
MViewHelp db "&View Help",0
MAbout db "&About RetroPad",0
AboutCap db "RetroPad",0
AboutText db "RetroPad - tiny notepad-style editor",0
SaveCap db "RetroPad",0
SaveAskText db "Save changes?",0
SpaceText db " ",0
DateBuf db 32 dup (0)
TimeBuf db 32 dup (0)
FileFilter db "All Files",0,"*.*",0,0
FindMsgStr db "commdlg_FindReplace",0
FindWhat db 128 dup (0) ; Find What text buffer
ReplaceWith db 128 dup (0) ; Replace With text buffer
fr FINDREPLACEA <> ; shared find/replace request
hFindDlg dd 0 ; modeless find/replace dialog HWND
uFindMsg dd 0 ; registered FINDMSGSTRING message
StaticClass db "STATIC",0 ; built-in class for status bar pane
DocName db "RetroPad",0 ; print job document name
LnColFmt db " Ln %d, Col %d",0 ; status bar Ln/Col format
StatusBuf db 48 dup (0) ; formatted Ln/Col text
hStatus dd 0 ; status bar window handle
fStatus dd 1 ; status bar visible flag (default ON)
hInst dd 0 ; module handle (for dialogs)
OpenVerb db "open",0 ; ShellExecute verb
HelpUrl db "https://github.com/davepl",0
; in-memory Go To dialog template (no font block to stay compact)
ALIGN 4
GoToTmpl LABEL DWORD
dd DS_MODALFRAME or WS_POPUP or WS_CAPTION or WS_SYSMENU
dd 0 ; exStyle
dw 2 ; control count
dw 0,0,150,46 ; x,y,cx,cy
dw 0 ; no menu
dw 0 ; default class
dw 'G','o',' ','T','o',0 ; caption
ALIGN 4
dd WS_CHILD or WS_VISIBLE or WS_BORDER or ES_NUMBER or WS_TABSTOP
dd 0
dw 7,7,136,12 ; edit rect
dw IDC_GOEDIT
dw 0FFFFh,0081h ; Edit class atom
dw 0 ; no caption
dw 0 ; no creation data
ALIGN 4
dd WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON or WS_TABSTOP
dd 0
dw 50,26,50,14 ; OK button rect
dw IDOK
dw 0FFFFh,0080h ; Button class atom
dw 'O','K',0 ; caption
dw 0 ; no creation data
; Rich Edit default font face: Courier only
RichFont dd 92 ; CHARFORMATW size
dd CFM_FACE ; only set face name
dd 0 ; no effects
dd 0 ; no font size change
dd 0 ; no offset change
dd 0 ; no color change
db 0 ; default charset
db 0 ; default pitch/family
dw 'C','o','u','r','i','e','r',0
dw 24 dup (0)
dw 0 ; CHARFORMATW padding
;----------------------------------------------;
.CODE ; Here is where the program itself lives ;
;----------------------------------------------;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; title bar caption from startup file name ;
; add "*" if the buffer has been modified ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BuildTitle proc NEAR
lea edi, TitleBuf
mov esi, OFFSET CmdFile
; no file argument: use Untitled
cmp byte ptr [esi], 0
jne FindFileTail
mov esi, OFFSET UntitledText
jmp CopyBase
; strip full path to filename when a file was provided
FindFileTail:
mov ebx, esi
FindTail:
mov al, [esi]
test al, al
je GotTail
cmp al, '\'
je MarkTail
;; surprised me disabling this works
;cmp al, '/'
;je MarkTail
;cmp al, ':'
;je MarkTail
inc esi
jmp FindTail
; record start of next path segment (looking for file name)
MarkTail:
mov ebx, esi
inc ebx
inc esi
jmp FindTail
; point to filename (tail of path)
GotTail:
mov esi, ebx
; copy the filename into the title buffer
CopyBase:
CopyLoop:
mov al, [esi]
test al, al
je CopyEnd
mov [edi], al
inc edi
inc esi
jmp CopyLoop
CopyEnd:
mov esi, OFFSET NotepadTail
; append " - Notepad"
CopyTail:
mov al, [esi]
mov [edi], al
inc edi
inc esi
test al, al
jne CopyTail
; done
TitleDone:
ret
BuildTitle endp ; end BuildTitle proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; build title and set title bar caption ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ApplyTitle proc NEAR
call BuildTitle
push OFFSET TitleBuf
mov eax, hMain
push eax
call [_imp__SetWindowTextA@8]
ret
ApplyTitle endp ;end ApplyTitle proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; parse command line for the startup file or ;
; if user drops a file on the app to launch ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ParseStartupFile proc NEAR
call [_imp__GetCommandLineA@0]
mov esi, eax
test esi, esi
je NoArg
cmp byte ptr [esi], '"'
jne SkipExeBare
inc esi
; skip quoted exe path so esi points to first argument
SkipExeQuoted:
mov al, [esi]
test al, al
je NoArg
inc esi
cmp al, '"'
jne SkipExeQuoted
jmp SkipWs
; skip unquoted exe path to reach first argument
SkipExeBare:
mov al, [esi]
test al, al
je NoArg
cmp al, ' '
je SkipWs
cmp al, 9
je SkipWs
inc esi
jmp SkipExeBare
; skip spaces/tabs before argument (white spaces)
SkipWs:
mov al, [esi]
cmp al, ' '
je SkipWsStep
cmp al, 9
je SkipWsStep
jmp ArgStart
; advance past whitespace
SkipWsStep:
inc esi
jmp SkipWs
; start copying first argument (file path), handle quoted
ArgStart:
cmp byte ptr [esi], 0
je NoArg
lea edi, CmdFile
mov ecx, MAX_CMD_PATH-1
cmp byte ptr [esi], '"'
jne CopyBare
inc esi
; copy quoted file path into CmdFile (strip quotes)
CopyQuoted:
mov al, [esi]
test al, al
je CopyDone
cmp al, '"'
je CopyDone
mov [edi], al
inc edi
inc esi
dec ecx
jz CopyDone
jmp CopyQuoted
; copy unquoted file path into CmdFile
CopyBare:
mov al, [esi]
test al, al
je CopyDone
cmp al, ' '
je CopyDone
cmp al, 9
je CopyDone
mov [edi], al
inc edi
inc esi
dec ecx
jz CopyDone
jmp CopyBare
; null-terminate CmdFile and return
CopyDone:
mov byte ptr [edi], 0
ret
; no arg: clear CmdFile (no startup file)
NoArg:
mov byte ptr [CmdFile], 0
ret
ParseStartupFile endp ; end ParseStartupFile proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; start a new empty document ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NewFile proc NEAR
mov byte ptr [CmdFile], 0
push OFFSET EmptyText
mov eax, hEdit
push eax
call [_imp__SetWindowTextA@8]
xor eax, eax
mov fDirty, eax
call ApplyTitle
ret
NewFile endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open-file dialog into CmdFile buffer ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PickOpenFile proc NEAR
LOCAL ofn:OPENFILENAMEA
push 19
pop ecx
xor eax, eax
lea edi, ofn
rep stosd
mov byte ptr [CmdFile], 0
mov ofn.lStructSize, SIZEOF OPENFILENAMEA
mov eax, hMain
mov ofn.hwndOwner, eax
mov ofn.lpstrFilter, OFFSET FileFilter
mov ofn.lpstrFile, OFFSET CmdFile
mov ofn.nMaxFile, MAX_CMD_PATH
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_HIDEREADONLY
lea eax, ofn
push eax
call [_imp__GetOpenFileNameA@4]
ret
PickOpenFile endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; save-file dialog into CmdFile buffer ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PickSaveFile proc NEAR
LOCAL ofn:OPENFILENAMEA
push 19
pop ecx
xor eax, eax
lea edi, ofn
rep stosd
mov ofn.lStructSize, SIZEOF OPENFILENAMEA
mov eax, hMain
mov ofn.hwndOwner, eax
mov ofn.lpstrFilter, OFFSET FileFilter
mov ofn.lpstrFile, OFFSET CmdFile
mov ofn.nMaxFile, MAX_CMD_PATH
mov ofn.Flags, OFN_PATHMUSTEXIST or OFN_HIDEREADONLY or OFN_OVERWRITEPROMPT
lea eax, ofn
push eax
call [_imp__GetSaveFileNameA@4]
ret
PickSaveFile endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ask user whether to save dirty buffer ;
; returns eax=1 continue / eax=0 cancel ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MaybeSaveChanges proc NEAR
cmp fDirty, 0
jne AskSave
push 1
pop eax
ret
AskSave:
push MB_YESNOCANCEL or MB_ICONQUESTION
push OFFSET SaveCap
push OFFSET SaveAskText
mov eax, hMain
push eax
call [_imp__MessageBoxA@16]
cmp eax, IDCANCEL
jne NotCancel
xor eax, eax
ret
NotCancel:
cmp eax, IDNO
jne NeedSave
push 1
pop eax
ret
NeedSave:
cmp byte ptr [CmdFile], 0
jne SaveNow
call PickSaveFile
test eax, eax
jne SaveNow
xor eax, eax
ret
SaveNow:
call SaveFile
push 1
pop eax
ret
MaybeSaveChanges endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; insert current date/time at caret ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InsertTimeDate proc NEAR
LOCAL sysTime:SYSTEMTIME
lea eax, sysTime
push eax
call [_imp__GetLocalTime@4]
push 32
push OFFSET DateBuf
push 0 ; lpFormat (use locale default)
lea eax, sysTime
push eax ; lpDate
push DATE_SHORTDATE ; dwFlags
push LOCALE_USER_DEFAULT
call [_imp__GetDateFormatA@24]
push 32
push OFFSET TimeBuf
push 0 ; lpFormat (use locale default)
lea eax, sysTime
push eax ; lpTime
push 0 ; dwFlags
push LOCALE_USER_DEFAULT
call [_imp__GetTimeFormatA@24]
push OFFSET DateBuf
push TRUE
push EM_REPLACESEL
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
push OFFSET SpaceText
push TRUE
push EM_REPLACESEL
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
push OFFSET TimeBuf
push TRUE
push EM_REPLACESEL
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
ret
InsertTimeDate endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; toggle Rich Edit word-wrap mode ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ToggleWrap proc NEAR
cmp fWrap, 0
je WrapOn
; wrap off: use a very wide target line
xor eax, eax
mov fWrap, eax
push 0FFFFFFFFh
push 0
push EM_SETTARGETDEVICE
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
ret
WrapOn:
push 1
pop eax
mov fWrap, eax
push 0
push 0
push EM_SETTARGETDEVICE
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
ret
ToggleWrap endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; pick a font via common dialog, apply to text ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ChooseFontDlg proc NEAR
LOCAL lf:LOGFONTW
LOCAL cf:CHOOSEFONTW
LOCAL fmt:CHARFORMATW
; zero CHOOSEFONT and LOGFONT structs
xor eax, eax
lea edi, cf
mov ecx, (SIZEOF CHOOSEFONTW)/4
rep stosd
lea edi, lf
mov ecx, (SIZEOF LOGFONTW)/4
rep stosd
mov cf.lStructSize, SIZEOF CHOOSEFONTW
mov eax, hMain
mov cf.hwndOwner, eax
lea eax, lf
mov cf.lpLogFont, eax
mov cf.Flags, CF_SCREENFONTS or CF_EFFECTS
lea eax, cf
push eax
call [_imp__ChooseFontW@4]
test eax, eax
je FontCancel
; build CHARFORMATW from chosen font
xor eax, eax
lea edi, fmt
mov ecx, (SIZEOF CHARFORMATW)/4
rep stosd
mov fmt.cbSize, SIZEOF CHARFORMATW
mov fmt.dwMask, CFM_FACE or CFM_SIZE or CFM_BOLD or CFM_ITALIC
; bold/italic effects
xor edx, edx
cmp lf.lfWeight, 700
jl FNoBold
or edx, CFE_BOLD
FNoBold:
cmp lf.lfItalic, 0
je FNoItal
or edx, CFE_ITALIC
FNoItal:
mov fmt.dwEffects, edx
; yHeight (twips) = iPointSize (1/10 pt) * 2
mov eax, cf.iPointSize
add eax, eax
mov fmt.yHeight, eax
; copy wide face name into CHARFORMATW
lea esi, lf.lfFaceName
lea edi, fmt.szFaceName
mov ecx, LF_FACESIZE
FCopyFace:
mov ax, [esi]
mov [edi], ax
add esi, 2
add edi, 2
test ax, ax
je FApply
dec ecx
jnz FCopyFace
FApply:
lea eax, fmt
push eax
push SCF_ALL
push EM_SETCHARFORMAT
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
FontCancel:
ret
ChooseFontDlg endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; fill shared FINDREPLACE request struct ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InitFR proc NEAR
xor eax, eax
lea edi, fr
mov ecx, (SIZEOF FINDREPLACEA)/4
rep stosd
mov fr.lStructSize, SIZEOF FINDREPLACEA
mov eax, hMain
mov fr.hwndOwner, eax
mov fr.lpstrFindWhat, OFFSET FindWhat
mov fr.wFindWhatLen, 128
mov fr.lpstrReplaceWith, OFFSET ReplaceWith
mov fr.wReplaceWithLen, 128
mov fr.Flags, FR_DOWN
ret
InitFR endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; find next match of FindWhat, select it ;
; returns eax=1 found / eax=0 not found ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DoFindNext proc NEAR
LOCAL ft:FINDTEXTEXA
LOCAL cr:CHARRANGE
; current selection range
lea eax, cr
push eax
push 0
push EM_EXGETSEL
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
; search from end of selection to end of text
mov eax, cr.cpMax
mov ft.chrg.cpMin, eax
mov ft.chrg.cpMax, -1
mov eax, OFFSET FindWhat
mov ft.lpstrText, eax
mov eax, fr.Flags
and eax, FR_MATCHCASE
or eax, FR_DOWN
lea edx, ft
push edx
push eax
push EM_FINDTEXTEXA
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
cmp eax, -1
je FindMiss
; select the match
lea edx, ft.chrgText
push edx
push 0
push EM_EXSETSEL
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
push 0
push 0
push EM_SCROLLCARET
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
push 1
pop eax
ret
FindMiss:
xor eax, eax
ret
DoFindNext endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; replace current match then advance ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DoReplaceOne proc NEAR
push OFFSET ReplaceWith
push TRUE
push EM_REPLACESEL
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
call DoFindNext
ret
DoReplaceOne endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; replace every match from the top ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DoReplaceAll proc NEAR
LOCAL cr:CHARRANGE
; move caret to start of text
mov cr.cpMin, 0
mov cr.cpMax, 0
lea eax, cr
push eax
push 0
push EM_EXSETSEL
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
RepLoop:
call DoFindNext
test eax, eax
jz RepDone
push OFFSET ReplaceWith
push TRUE
push EM_REPLACESEL
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
jmp RepLoop
RepDone:
ret
DoReplaceAll endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dispatch a FINDMSGSTRING notification ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OnFindReplaceMsg proc NEAR
mov eax, fr.Flags
test eax, FR_DIALOGTERM
jz NotTerm
mov dword ptr hFindDlg, 0
ret
NotTerm:
test eax, FR_REPLACEALL
jz NotRepAll
call DoReplaceAll
ret
NotRepAll:
test eax, FR_REPLACE
jz JustFind
call DoReplaceOne
ret
JustFind:
call DoFindNext
ret
OnFindReplaceMsg endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; print document via common dialog + Rich Edit ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PrintDoc proc NEAR
LOCAL pd:PRINTDLGA
LOCAL docInf:DOCINFOA
LOCAL fmt:FORMATRANGE
LOCAL txtLen:DWORD
LOCAL hPrnDC:DWORD
; show Print dialog, request a printer DC
xor eax, eax
lea edi, pd
mov ecx, SIZEOF PRINTDLGA
rep stosb
mov pd.lStructSize, SIZEOF PRINTDLGA
mov eax, hMain
mov pd.hwndOwner, eax
mov pd.Flags, PD_RETURNDC or PD_NOPAGENUMS or PD_NOSELECTION
lea eax, pd
push eax
call [_imp__PrintDlgA@4]
test eax, eax
je PrintCancel
mov eax, pd.hDC
mov hPrnDC, eax
; begin document
xor eax, eax
lea edi, docInf
mov ecx, SIZEOF DOCINFOA
rep stosb
mov docInf.cbSize, SIZEOF DOCINFOA
mov docInf.lpszDocName, OFFSET DocName
lea eax, docInf
push eax
push hPrnDC
call [_imp__StartDocA@8]
; prepare FORMATRANGE
xor eax, eax
lea edi, fmt
mov ecx, SIZEOF FORMATRANGE
rep stosb
mov eax, hPrnDC
mov fmt.hdc, eax
mov fmt.hdcTarget, eax
; page width in twips = HORZRES * 1440 / LOGPIXELSX
push HORZRES
push hPrnDC
call [_imp__GetDeviceCaps@8]
mov esi, eax
push LOGPIXELSX
push hPrnDC
call [_imp__GetDeviceCaps@8]
mov ecx, eax
mov eax, esi
imul eax, 1440
xor edx, edx
div ecx
mov fmt.rc.right, eax
mov fmt.rcPage.right, eax
; page height in twips = VERTRES * 1440 / LOGPIXELSY
push VERTRES
push hPrnDC
call [_imp__GetDeviceCaps@8]
mov esi, eax
push LOGPIXELSY
push hPrnDC
call [_imp__GetDeviceCaps@8]
mov ecx, eax
mov eax, esi
imul eax, 1440
xor edx, edx
div ecx
mov fmt.rc.bottom, eax
mov fmt.rcPage.bottom, eax
; render range = whole document
push 0
push 0
push WM_GETTEXTLENGTH
mov eax, hEdit
push eax
call [_imp__SendMessageA@16]
mov txtLen, eax
mov fmt.chrg.cpMin, 0
mov fmt.chrg.cpMax, eax
PrintPage:
push hPrnDC
call [_imp__StartPage@4]
lea eax, fmt
push eax
push TRUE
push EM_FORMATRANGE
mov edx, hEdit
push edx
call [_imp__SendMessageA@16]
mov fmt.chrg.cpMin, eax ; next page starts here
push eax