dialog.c 26.1 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 *  Notepad (dialog.c)
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
4
 *  Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5
 *  Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6
 *  Copyright 2002 Andriy Palamarchuk
7
 *  Copyright 2007 Rolf Kalbermatter
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23
 */

24
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <stdio.h>
26 27
#include <windows.h>
#include <commdlg.h>
28
#include <shlwapi.h>
29

Alexandre Julliard's avatar
Alexandre Julliard committed
30 31
#include "main.h"
#include "dialog.h"
32

33
#define SPACES_IN_TAB 8
34
#define PRINT_LEN_MAX 500
35

36
static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 };
Alexandre Julliard's avatar
Alexandre Julliard committed
37

38
static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
39

40
VOID ShowLastError(void)
41 42 43 44
{
    DWORD error = GetLastError();
    if (error != NO_ERROR)
    {
45 46
        LPWSTR lpMsgBuf;
        WCHAR szTitle[MAX_STRING_LEN];
47

48
        LoadStringW(Globals.hInstance, STRING_ERROR, szTitle, ARRAY_SIZE(szTitle));
49
        FormatMessageW(
50
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
51
            NULL, error, 0, (LPWSTR)&lpMsgBuf, 0, NULL);
52
        MessageBoxW(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
53 54 55 56 57 58
        LocalFree(lpMsgBuf);
    }
}

/**
 * Sets the caption of the main window according to Globals.szFileTitle:
59 60
 *    Untitled - Notepad        if no file is open
 *    filename - Notepad        if a file is given
61
 */
62 63 64
static void UpdateWindowCaption(void)
{
  WCHAR szCaption[MAX_STRING_LEN];
65 66
  WCHAR szNotepad[MAX_STRING_LEN];
  static const WCHAR hyphenW[] = { ' ','-',' ',0 };
67

68
  if (Globals.szFileTitle[0] != '\0')
69
      lstrcpyW(szCaption, Globals.szFileTitle);
70
  else
71
      LoadStringW(Globals.hInstance, STRING_UNTITLED, szCaption, ARRAY_SIZE(szCaption));
72

73
  LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
74 75
  lstrcatW(szCaption, hyphenW);
  lstrcatW(szCaption, szNotepad);
76

77
  SetWindowTextW(Globals.hMainWnd, szCaption);
78 79
}

80
int DIALOG_StringMsgBox(HWND hParent, int formatId, LPCWSTR szString, DWORD dwFlags)
81 82 83
{
   WCHAR szMessage[MAX_STRING_LEN];
   WCHAR szResource[MAX_STRING_LEN];
84 85

   /* Load and format szMessage */
86 87
   LoadStringW(Globals.hInstance, formatId, szResource, ARRAY_SIZE(szResource));
   wnsprintfW(szMessage, ARRAY_SIZE(szMessage), szResource, szString);
88

89
   /* Load szCaption */
90
   if ((dwFlags & MB_ICONMASK) == MB_ICONEXCLAMATION)
91
     LoadStringW(Globals.hInstance, STRING_ERROR,  szResource, ARRAY_SIZE(szResource));
92
   else
93
     LoadStringW(Globals.hInstance, STRING_NOTEPAD,  szResource, ARRAY_SIZE(szResource));
94 95

   /* Display Modal Dialog */
96 97
   if (hParent == NULL)
     hParent = Globals.hMainWnd;
98
   return MessageBoxW(hParent, szMessage, szResource, dwFlags);
99 100 101 102 103
}

static void AlertFileNotFound(LPCWSTR szFileName)
{
   DIALOG_StringMsgBox(NULL, STRING_NOTFOUND, szFileName, MB_ICONEXCLAMATION|MB_OK);
Alexandre Julliard's avatar
Alexandre Julliard committed
104 105
}

106 107 108
static int AlertFileNotSaved(LPCWSTR szFileName)
{
   WCHAR szUntitled[MAX_STRING_LEN];
Alexandre Julliard's avatar
Alexandre Julliard committed
109

110
   LoadStringW(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
111 112
   return DIALOG_StringMsgBox(NULL, STRING_NOTSAVED, szFileName[0] ? szFileName : szUntitled,
     MB_ICONQUESTION|MB_YESNOCANCEL);
113 114
}

115 116 117 118
/**
 * Returns:
 *   TRUE  - if file exists
 *   FALSE - if file does not exist
Alexandre Julliard's avatar
Alexandre Julliard committed
119
 */
120 121
BOOL FileExists(LPCWSTR szFilename)
{
122
   WIN32_FIND_DATAW entry;
123
   HANDLE hFile;
124

125
   hFile = FindFirstFileW(szFilename, &entry);
126
   FindClose(hFile);
127

128
   return (hFile != INVALID_HANDLE_VALUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
129 130
}

131

132 133
static VOID DoSaveFile(VOID)
{
134 135
    HANDLE hFile;
    DWORD dwNumWrite;
136 137
    LPSTR pTemp;
    DWORD size;
138

139
    hFile = CreateFileW(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
140 141 142 143 144 145
                       NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hFile == INVALID_HANDLE_VALUE)
    {
        ShowLastError();
        return;
    }
146

147 148
    size = GetWindowTextLengthA(Globals.hEdit) + 1;
    pTemp = HeapAlloc(GetProcessHeap(), 0, size);
149 150
    if (!pTemp)
    {
151
	CloseHandle(hFile);
152 153 154
        ShowLastError();
        return;
    }
155
    size = GetWindowTextA(Globals.hEdit, pTemp, size);
Alexandre Julliard's avatar
Alexandre Julliard committed
156

157
    if (!WriteFile(hFile, pTemp, size, &dwNumWrite, NULL))
158
        ShowLastError();
159
    else
160
        SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
161

162
    SetEndOfFile(hFile);
163
    CloseHandle(hFile);
164
    HeapFree(GetProcessHeap(), 0, pTemp);
165
}
Alexandre Julliard's avatar
Alexandre Julliard committed
166

167 168 169 170 171
/**
 * Returns:
 *   TRUE  - User agreed to close (both save/don't save)
 *   FALSE - User cancelled close by selecting "Cancel"
 */
172 173
BOOL DoCloseFile(void)
{
174
    int nResult;
175
    static const WCHAR empty_strW[] = { 0 };
176

177
    if (SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0))
178
    {
179 180 181
        /* prompt user to save changes */
        nResult = AlertFileNotSaved(Globals.szFileName);
        switch (nResult) {
182
            case IDYES:     return DIALOG_FileSave();
Alexandre Julliard's avatar
Alexandre Julliard committed
183

184
            case IDNO:      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
185

186
            case IDCANCEL:  return(FALSE);
187

188 189 190
            default:        return(FALSE);
        } /* switch */
    } /* if */
191

192
    SetFileName(empty_strW);
193 194

    UpdateWindowCaption();
195
    return(TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
196 197 198
}


199 200
void DoOpenFile(LPCWSTR szFileName)
{
201
    static const WCHAR dotlog[] = { '.','L','O','G',0 };
202 203 204 205
    HANDLE hFile;
    LPSTR pTemp;
    DWORD size;
    DWORD dwNumRead;
206
    WCHAR log[5];
207

208
    /* Close any files and prompt to save changes */
209 210 211
    if (!DoCloseFile())
	return;

212 213
    hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
214
    if(hFile == INVALID_HANDLE_VALUE)
215
    {
216
	AlertFileNotFound(szFileName);
217 218
	return;
    }
219

220
    size = GetFileSize(hFile, NULL);
221
    if (size == INVALID_FILE_SIZE)
222 223 224 225 226 227
    {
	CloseHandle(hFile);
	ShowLastError();
	return;
    }
    size++;
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242
    pTemp = HeapAlloc(GetProcessHeap(), 0, size);
    if (!pTemp)
    {
	CloseHandle(hFile);
	ShowLastError();
	return;
    }

    if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
    {
	CloseHandle(hFile);
	HeapFree(GetProcessHeap(), 0, pTemp);
	ShowLastError();
	return;
Alexandre Julliard's avatar
Alexandre Julliard committed
243
    }
244 245 246 247

    CloseHandle(hFile);
    pTemp[dwNumRead] = 0;

248 249
    if((size -1) >= 2 && (BYTE)pTemp[0] == 0xff && (BYTE)pTemp[1] == 0xfe)
	SetWindowTextW(Globals.hEdit, (LPWSTR)pTemp + 1);
250 251 252 253 254
    else
	SetWindowTextA(Globals.hEdit, pTemp);

    HeapFree(GetProcessHeap(), 0, pTemp);

255 256
    SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
    SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
257
    SetFocus(Globals.hEdit);
258
    
259
    /*  If the file starts with .LOG, add a time/date at the end and set cursor after */
260
    if (GetWindowTextW(Globals.hEdit, log, ARRAY_SIZE(log)) && !lstrcmpW(log, dotlog))
261 262
    {
	static const WCHAR lfW[] = { '\r','\n',0 };
263
        SendMessageW(Globals.hEdit, EM_SETSEL, GetWindowTextLengthW(Globals.hEdit), -1);
264
        SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
265
	DIALOG_EditTimeDate();
266
        SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
267
    }
268 269 270

    SetFileName(szFileName);
    UpdateWindowCaption();
Alexandre Julliard's avatar
Alexandre Julliard committed
271 272
}

Alexandre Julliard's avatar
Alexandre Julliard committed
273 274
VOID DIALOG_FileNew(VOID)
{
275 276
    static const WCHAR empty_strW[] = { 0 };

277
    /* Close any files and prompt to save changes */
Alexandre Julliard's avatar
Alexandre Julliard committed
278
    if (DoCloseFile()) {
279
        SetWindowTextW(Globals.hEdit, empty_strW);
280
        SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
281
        SetFocus(Globals.hEdit);
Alexandre Julliard's avatar
Alexandre Julliard committed
282
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
283 284 285 286
}

VOID DIALOG_FileOpen(VOID)
{
287
    OPENFILENAMEW openfilename;
288 289 290 291
    WCHAR szPath[MAX_PATH];
    WCHAR szDir[MAX_PATH];
    static const WCHAR szDefaultExt[] = { 't','x','t',0 };
    static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
292 293 294

    ZeroMemory(&openfilename, sizeof(openfilename));

295
    GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
296
    lstrcpyW(szPath, txt_files);
297 298 299 300 301 302

    openfilename.lStructSize       = sizeof(openfilename);
    openfilename.hwndOwner         = Globals.hMainWnd;
    openfilename.hInstance         = Globals.hInstance;
    openfilename.lpstrFilter       = Globals.szFilter;
    openfilename.lpstrFile         = szPath;
303
    openfilename.nMaxFile          = ARRAY_SIZE(szPath);
304 305
    openfilename.lpstrInitialDir   = szDir;
    openfilename.Flags             = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
306
        OFN_HIDEREADONLY | OFN_ENABLESIZING;
307 308 309
    openfilename.lpstrDefExt       = szDefaultExt;


310
    if (GetOpenFileNameW(&openfilename))
311
        DoOpenFile(openfilename.lpstrFile);
Alexandre Julliard's avatar
Alexandre Julliard committed
312 313
}

314

315
BOOL DIALOG_FileSave(VOID)
Alexandre Julliard's avatar
Alexandre Julliard committed
316
{
317
    if (Globals.szFileName[0] == '\0')
318
        return DIALOG_FileSaveAs();
319 320
    else
        DoSaveFile();
321
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
322 323
}

324
BOOL DIALOG_FileSaveAs(VOID)
Alexandre Julliard's avatar
Alexandre Julliard committed
325
{
326
    OPENFILENAMEW saveas;
327 328 329 330
    WCHAR szPath[MAX_PATH];
    WCHAR szDir[MAX_PATH];
    static const WCHAR szDefaultExt[] = { 't','x','t',0 };
    static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
331 332 333

    ZeroMemory(&saveas, sizeof(saveas));

334
    GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
335
    lstrcpyW(szPath, txt_files);
336

337
    saveas.lStructSize       = sizeof(OPENFILENAMEW);
338 339 340 341
    saveas.hwndOwner         = Globals.hMainWnd;
    saveas.hInstance         = Globals.hInstance;
    saveas.lpstrFilter       = Globals.szFilter;
    saveas.lpstrFile         = szPath;
342
    saveas.nMaxFile          = ARRAY_SIZE(szPath);
343 344
    saveas.lpstrInitialDir   = szDir;
    saveas.Flags             = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
345
        OFN_HIDEREADONLY | OFN_ENABLESIZING;
346 347
    saveas.lpstrDefExt       = szDefaultExt;

348
    if (GetSaveFileNameW(&saveas)) {
349 350 351
        SetFileName(szPath);
        UpdateWindowCaption();
        DoSaveFile();
352
        return TRUE;
353
    }
354
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
355 356
}

357 358 359 360 361 362 363 364 365 366 367 368 369 370
typedef struct {
    LPWSTR mptr;
    LPWSTR mend;
    LPWSTR lptr;
    DWORD len;
} TEXTINFO, *LPTEXTINFO;

static int notepad_print_header(HDC hdc, RECT *rc, BOOL dopage, BOOL header, int page, LPWSTR text)
{
    SIZE szMetric;

    if (*text)
    {
        /* Write the header or footer */
371
        GetTextExtentPoint32W(hdc, text, lstrlenW(text), &szMetric);
372
        if (dopage)
373 374 375
            ExtTextOutW(hdc, (rc->left + rc->right - szMetric.cx) / 2,
                        header ? rc->top : rc->bottom - szMetric.cy,
                        ETO_CLIPPED, rc, text, lstrlenW(text), NULL);
376 377 378 379 380 381 382 383
        return 1;
    }
    return 0;
}

static BOOL notepad_print_page(HDC hdc, RECT *rc, BOOL dopage, int page, LPTEXTINFO tInfo)
{
    int b, y;
384
    TEXTMETRICW tm;
385 386 387 388 389 390 391 392
    SIZE szMetrics;

    if (dopage)
    {
        if (StartPage(hdc) <= 0)
        {
            static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 };
            static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 };
393
            MessageBoxW(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION);
394 395 396 397
            return FALSE;
        }
    }

398
    GetTextMetricsW(hdc, &tm);
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
    y = rc->top + notepad_print_header(hdc, rc, dopage, TRUE, page, Globals.szFileName) * tm.tmHeight;
    b = rc->bottom - 2 * notepad_print_header(hdc, rc, FALSE, FALSE, page, Globals.szFooter) * tm.tmHeight;

    do {
        INT m, n;

        if (!tInfo->len)
        {
            /* find the end of the line */
            while (tInfo->mptr < tInfo->mend && *tInfo->mptr != '\n' && *tInfo->mptr != '\r')
            {
                if (*tInfo->mptr == '\t')
                {
                    /* replace tabs with spaces */
                    for (m = 0; m < SPACES_IN_TAB; m++)
                    {
                        if (tInfo->len < PRINT_LEN_MAX)
                            tInfo->lptr[tInfo->len++] = ' ';
                        else if (Globals.bWrapLongLines)
                            break;
                    }
                }
                else if (tInfo->len < PRINT_LEN_MAX)
                    tInfo->lptr[tInfo->len++] = *tInfo->mptr;

                if (tInfo->len >= PRINT_LEN_MAX && Globals.bWrapLongLines)
                     break;

                tInfo->mptr++;
            }
        }

        /* Find out how much we should print if line wrapping is enabled */
        if (Globals.bWrapLongLines)
        {
434
            GetTextExtentExPointW(hdc, tInfo->lptr, tInfo->len, rc->right - rc->left, &n, NULL, &szMetrics);
435 436 437 438 439 440 441 442 443 444 445 446
            if (n < tInfo->len && tInfo->lptr[n] != ' ')
            {
                m = n;
                /* Don't wrap words unless it's a single word over the entire line */
                while (m  && tInfo->lptr[m] != ' ') m--;
                if (m > 0) n = m + 1;
            }
        }
        else
            n = tInfo->len;

        if (dopage)
447
            ExtTextOutW(hdc, rc->left, y, ETO_CLIPPED, rc, tInfo->lptr, n, NULL);
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

        tInfo->len -= n;

        if (tInfo->len)
        {
            memcpy(tInfo->lptr, tInfo->lptr + n, tInfo->len * sizeof(WCHAR));
            y += tm.tmHeight + tm.tmExternalLeading;
        }
        else
        {
            /* find the next line */
            while (tInfo->mptr < tInfo->mend && y < b && (*tInfo->mptr == '\n' || *tInfo->mptr == '\r'))
            {
                if (*tInfo->mptr == '\n')
                    y += tm.tmHeight + tm.tmExternalLeading;
                tInfo->mptr++;
            }
        }
    } while (tInfo->mptr < tInfo->mend && y < b);

    notepad_print_header(hdc, rc, dopage, FALSE, page, Globals.szFooter);
    if (dopage)
    {
        EndPage(hdc);
    }
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
476 477
VOID DIALOG_FilePrint(VOID)
{
478 479
    DOCINFOW di;
    PRINTDLGW printer;
480
    int page, dopage, copy;
481
    LOGFONTW lfFont;
482
    HFONT hTextFont, old_font = 0;
483
    DWORD size;
484 485
    BOOL ret = FALSE;
    RECT rc;
486
    LPWSTR pTemp;
487
    TEXTINFO tInfo;
488
    WCHAR cTemp[PRINT_LEN_MAX];
489

490 491 492 493
    /* Get Current Settings */
    ZeroMemory(&printer, sizeof(printer));
    printer.lStructSize           = sizeof(printer);
    printer.hwndOwner             = Globals.hMainWnd;
494 495
    printer.hDevMode              = Globals.hDevMode;
    printer.hDevNames             = Globals.hDevNames;
496
    printer.hInstance             = Globals.hInstance;
497

498
    /* Set some default flags */
499
    printer.Flags                 = PD_RETURNDC | PD_NOSELECTION;
500
    printer.nFromPage             = 0;
501 502
    printer.nMinPage              = 1;
    /* we really need to calculate number of pages to set nMaxPage and nToPage */
503 504
    printer.nToPage               = 0;
    printer.nMaxPage              = -1;
505 506 507
    /* Let commdlg manage copy settings */
    printer.nCopies               = (WORD)PD_USEDEVMODECOPIES;

508
    if (!PrintDlgW(&printer)) return;
509

510 511 512
    Globals.hDevMode = printer.hDevMode;
    Globals.hDevNames = printer.hDevNames;

513
    SetMapMode(printer.hDC, MM_TEXT);
514

515
    /* initialize DOCINFO */
516
    di.cbSize = sizeof(DOCINFOW);
517 518 519
    di.lpszDocName = Globals.szFileTitle;
    di.lpszOutput = NULL;
    di.lpszDatatype = NULL;
520 521 522
    di.fwType = 0; 

    /* Get the file text */
523
    size = GetWindowTextLengthW(Globals.hEdit) + 1;
524
    pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
525 526
    if (!pTemp)
    {
527 528 529
       DeleteDC(printer.hDC);
       ShowLastError();
       return;
530
    }
531
    size = GetWindowTextW(Globals.hEdit, pTemp, size);
532

533
    if (StartDocW(printer.hDC, &di) > 0)
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
    {
        /* Get the page margins in pixels. */
        rc.top =    MulDiv(Globals.iMarginTop, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540) -
                    GetDeviceCaps(printer.hDC, PHYSICALOFFSETY);
        rc.bottom = GetDeviceCaps(printer.hDC, PHYSICALHEIGHT) -
                    MulDiv(Globals.iMarginBottom, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540);
        rc.left =   MulDiv(Globals.iMarginLeft, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540) -
                    GetDeviceCaps(printer.hDC, PHYSICALOFFSETX);
        rc.right =  GetDeviceCaps(printer.hDC, PHYSICALWIDTH) -
                    MulDiv(Globals.iMarginRight, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540);

        /* Create a font for the printer resolution */
        lfFont = Globals.lfFont;
        lfFont.lfHeight = MulDiv(lfFont.lfHeight, GetDeviceCaps(printer.hDC, LOGPIXELSY), get_dpi());
        /* Make the font a bit lighter */
        lfFont.lfWeight -= 100;
550
        hTextFont = CreateFontIndirectW(&lfFont);
551 552 553 554 555 556 557 558 559 560 561
        old_font = SelectObject(printer.hDC, hTextFont);

        for (copy = 1; copy <= printer.nCopies; copy++)
        {
            page = 1;

            tInfo.mptr = pTemp;
            tInfo.mend = pTemp + size;
            tInfo.lptr = cTemp;
            tInfo.len = 0;

562
            do {
563 564 565 566 567 568 569 570 571 572 573
                if (printer.Flags & PD_PAGENUMS)
                {
                    /* a specific range of pages is selected, so
                     * skip pages that are not to be printed
                     */
                    if (page > printer.nToPage)
                        break;
                    else if (page >= printer.nFromPage)
                        dopage = 1;
                    else
                        dopage = 0;
574
                }
575 576 577 578 579 580
                else
                    dopage = 1;

                ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo);
                page++;
            } while (ret && tInfo.mptr < tInfo.mend);
581

582 583 584 585 586 587
            if (!ret) break;
        }
        EndDoc(printer.hDC);
        SelectObject(printer.hDC, old_font);
        DeleteObject(hTextFont);
    }
588
    DeleteDC(printer.hDC);
589
    HeapFree(GetProcessHeap(), 0, pTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
590 591 592 593
}

VOID DIALOG_FilePrinterSetup(VOID)
{
594
    PRINTDLGW printer;
595

596 597 598
    ZeroMemory(&printer, sizeof(printer));
    printer.lStructSize         = sizeof(printer);
    printer.hwndOwner           = Globals.hMainWnd;
599 600
    printer.hDevMode            = Globals.hDevMode;
    printer.hDevNames           = Globals.hDevNames;
601 602 603
    printer.hInstance           = Globals.hInstance;
    printer.Flags               = PD_PRINTSETUP;
    printer.nCopies             = 1;
604

605
    PrintDlgW(&printer);
606 607 608

    Globals.hDevMode = printer.hDevMode;
    Globals.hDevNames = printer.hDevNames;
Alexandre Julliard's avatar
Alexandre Julliard committed
609 610 611 612
}

VOID DIALOG_FileExit(VOID)
{
613
    PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0l);
Alexandre Julliard's avatar
Alexandre Julliard committed
614 615 616 617
}

VOID DIALOG_EditUndo(VOID)
{
618
    SendMessageW(Globals.hEdit, EM_UNDO, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620 621 622
}

VOID DIALOG_EditCut(VOID)
{
623
    SendMessageW(Globals.hEdit, WM_CUT, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
624 625 626 627
}

VOID DIALOG_EditCopy(VOID)
{
628
    SendMessageW(Globals.hEdit, WM_COPY, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630 631 632
}

VOID DIALOG_EditPaste(VOID)
{
633
    SendMessageW(Globals.hEdit, WM_PASTE, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
634 635 636 637
}

VOID DIALOG_EditDelete(VOID)
{
638
    SendMessageW(Globals.hEdit, WM_CLEAR, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
639 640 641 642
}

VOID DIALOG_EditSelectAll(VOID)
{
643
    SendMessageW(Globals.hEdit, EM_SETSEL, 0, -1);
Alexandre Julliard's avatar
Alexandre Julliard committed
644 645 646 647
}

VOID DIALOG_EditTimeDate(VOID)
{
648
    SYSTEMTIME   st;
649 650
    WCHAR        szDate[MAX_STRING_LEN];
    static const WCHAR spaceW[] = { ' ',0 };
651

652
    GetLocalTime(&st);
653

654
    GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szDate, MAX_STRING_LEN);
655
    SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
656

657
    SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)spaceW);
658

659
    GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
660
    SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
Alexandre Julliard's avatar
Alexandre Julliard committed
661 662 663 664
}

VOID DIALOG_EditWrap(VOID)
{
665
    BOOL modify = FALSE;
Lauri Tulmin's avatar
Lauri Tulmin committed
666 667 668 669 670 671 672
    static const WCHAR editW[] = { 'e','d','i','t',0 };
    DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
                    ES_AUTOVSCROLL | ES_MULTILINE;
    RECT rc;
    DWORD size;
    LPWSTR pTemp;

673
    size = GetWindowTextLengthW(Globals.hEdit) + 1;
Lauri Tulmin's avatar
Lauri Tulmin committed
674 675 676 677 678 679
    pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
    if (!pTemp)
    {
        ShowLastError();
        return;
    }
680
    GetWindowTextW(Globals.hEdit, pTemp, size);
681
    modify = SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0);
Lauri Tulmin's avatar
Lauri Tulmin committed
682 683 684
    DestroyWindow(Globals.hEdit);
    GetClientRect(Globals.hMainWnd, &rc);
    if( Globals.bWrapLongLines ) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
685
    Globals.hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, editW, NULL, dwStyle,
Lauri Tulmin's avatar
Lauri Tulmin committed
686 687
                         0, 0, rc.right, rc.bottom, Globals.hMainWnd,
                         NULL, Globals.hInstance, NULL);
688
    SendMessageW(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
Lauri Tulmin's avatar
Lauri Tulmin committed
689
    SetWindowTextW(Globals.hEdit, pTemp);
690
    SendMessageW(Globals.hEdit, EM_SETMODIFY, modify, 0);
Lauri Tulmin's avatar
Lauri Tulmin committed
691 692 693
    SetFocus(Globals.hEdit);
    HeapFree(GetProcessHeap(), 0, pTemp);
    
694 695 696
    Globals.bWrapLongLines = !Globals.bWrapLongLines;
    CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
        MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
Alexandre Julliard's avatar
Alexandre Julliard committed
697 698
}

699 700
VOID DIALOG_SelectFont(VOID)
{
701 702
    CHOOSEFONTW cf;
    LOGFONTW lf=Globals.lfFont;
703 704 705 706 707

    ZeroMemory( &cf, sizeof(cf) );
    cf.lStructSize=sizeof(cf);
    cf.hwndOwner=Globals.hMainWnd;
    cf.lpLogFont=&lf;
708
    cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
709

710
    if( ChooseFontW(&cf) )
711 712 713
    {
        HFONT currfont=Globals.hFont;

714
        Globals.hFont=CreateFontIndirectW( &lf );
715
        Globals.lfFont=lf;
716
        SendMessageW( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, TRUE );
717 718 719 720 721
        if( currfont!=NULL )
            DeleteObject( currfont );
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
722 723
VOID DIALOG_Search(VOID)
{
724 725 726 727 728 729 730
        /* Allow only one search/replace dialog to open */
        if(Globals.hFindReplaceDlg != NULL)
        {
            SetActiveWindow(Globals.hFindReplaceDlg);
            return;
        }

731
        ZeroMemory(&Globals.find, sizeof(Globals.find));
732 733 734
        Globals.find.lStructSize      = sizeof(Globals.find);
        Globals.find.hwndOwner        = Globals.hMainWnd;
        Globals.find.hInstance        = Globals.hInstance;
735
        Globals.find.lpstrFindWhat    = Globals.szFindText;
736
        Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
737
        Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;
738 739 740

        /* We only need to create the modal FindReplace dialog which will */
        /* notify us of incoming events using hMainWnd Window Messages    */
741

742
        Globals.hFindReplaceDlg = FindTextW(&Globals.find);
743
        assert(Globals.hFindReplaceDlg !=0);
Alexandre Julliard's avatar
Alexandre Julliard committed
744 745 746 747
}

VOID DIALOG_SearchNext(VOID)
{
748 749 750 751
    if (Globals.lastFind.lpstrFindWhat == NULL)
        DIALOG_Search();
    else                /* use the last find data */
        NOTEPAD_DoFind(&Globals.lastFind);
Alexandre Julliard's avatar
Alexandre Julliard committed
752 753
}

754 755
VOID DIALOG_Replace(VOID)
{
756 757 758 759 760 761 762
        /* Allow only one search/replace dialog to open */
        if(Globals.hFindReplaceDlg != NULL)
        {
            SetActiveWindow(Globals.hFindReplaceDlg);
            return;
        }

763 764 765 766 767
        ZeroMemory(&Globals.find, sizeof(Globals.find));
        Globals.find.lStructSize      = sizeof(Globals.find);
        Globals.find.hwndOwner        = Globals.hMainWnd;
        Globals.find.hInstance        = Globals.hInstance;
        Globals.find.lpstrFindWhat    = Globals.szFindText;
768
        Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
769
        Globals.find.lpstrReplaceWith = Globals.szReplaceText;
770
        Globals.find.wReplaceWithLen  = ARRAY_SIZE(Globals.szReplaceText);
771 772 773 774 775
        Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;

        /* We only need to create the modal FindReplace dialog which will */
        /* notify us of incoming events using hMainWnd Window Messages    */

776
        Globals.hFindReplaceDlg = ReplaceTextW(&Globals.find);
777 778 779
        assert(Globals.hFindReplaceDlg !=0);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
780 781
VOID DIALOG_HelpContents(VOID)
{
782
    WinHelpW(Globals.hMainWnd, helpfileW, HELP_INDEX, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
783 784 785 786
}

VOID DIALOG_HelpSearch(VOID)
{
787
        /* Search Help */
Alexandre Julliard's avatar
Alexandre Julliard committed
788 789 790 791
}

VOID DIALOG_HelpHelp(VOID)
{
792
    WinHelpW(Globals.hMainWnd, helpfileW, HELP_HELPONHELP, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
793 794
}

795
VOID DIALOG_HelpAboutNotepad(VOID)
Alexandre Julliard's avatar
Alexandre Julliard committed
796
{
797
    static const WCHAR notepadW[] = { 'W','i','n','e',' ','N','o','t','e','p','a','d',0 };
798
    WCHAR szNotepad[MAX_STRING_LEN];
799 800
    HICON icon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD),
                            IMAGE_ICON, 48, 48, LR_SHARED);
801

802
    LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
803
    ShellAboutW(Globals.hMainWnd, szNotepad, notepadW, icon);
Alexandre Julliard's avatar
Alexandre Julliard committed
804 805
}

806

Alexandre Julliard's avatar
Alexandre Julliard committed
807 808
/***********************************************************************
 *
809
 *           DIALOG_FilePageSetup
Alexandre Julliard's avatar
Alexandre Julliard committed
810
 */
811
VOID DIALOG_FilePageSetup(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
812
{
813 814
    DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(DIALOG_PAGESETUP),
               Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
Alexandre Julliard's avatar
Alexandre Julliard committed
815 816 817 818 819 820 821 822
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *           DIALOG_PAGESETUP_DlgProc
 */

823
static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
824
{
825 826

   switch (msg)
Alexandre Julliard's avatar
Alexandre Julliard committed
827 828 829
    {
    case WM_COMMAND:
      switch (wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
830 831
        {
        case IDOK:
832
          /* save user input and close dialog */
833 834
          GetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
          GetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
835 836 837 838 839

          Globals.iMarginTop = GetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, NULL, FALSE) * 100;
          Globals.iMarginBottom = GetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, NULL, FALSE) * 100;
          Globals.iMarginLeft = GetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, NULL, FALSE) * 100;
          Globals.iMarginRight = GetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, NULL, FALSE) * 100;
Alexandre Julliard's avatar
Alexandre Julliard committed
840 841 842 843
          EndDialog(hDlg, IDOK);
          return TRUE;

        case IDCANCEL:
844
          /* discard user input and close dialog */
Alexandre Julliard's avatar
Alexandre Julliard committed
845 846
          EndDialog(hDlg, IDCANCEL);
          return TRUE;
847 848

        case IDHELP:
849
        {
850
          /* FIXME: Bring this to work */
851 852
          static const WCHAR sorryW[] = { 'S','o','r','r','y',',',' ','n','o',' ','h','e','l','p',' ','a','v','a','i','l','a','b','l','e',0 };
          static const WCHAR helpW[] = { 'H','e','l','p',0 };
853
          MessageBoxW(Globals.hMainWnd, sorryW, helpW, MB_ICONEXCLAMATION);
854
          return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
855
        }
856 857 858 859

	default:
	    break;
        }
860 861 862
      break;

    case WM_INITDIALOG:
863
       /* fetch last user input prior to display dialog */
864 865
       SetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader);
       SetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter);
866 867 868 869
       SetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, Globals.iMarginTop / 100, FALSE);
       SetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, Globals.iMarginBottom / 100, FALSE);
       SetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, Globals.iMarginLeft / 100, FALSE);
       SetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, Globals.iMarginRight / 100, FALSE);
870
       break;
Alexandre Julliard's avatar
Alexandre Julliard committed
871
    }
872

Alexandre Julliard's avatar
Alexandre Julliard committed
873 874
  return FALSE;
}