Exemplo n.º 1
0
bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
{
    wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );

    TC_ITEM tcItem;
    tcItem.mask = TCIF_TEXT;
    tcItem.pszText = wxMSW_CONV_LPTSTR(strText);

    if ( !HasFlag(wxNB_MULTILINE) )
        return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;

    // multiline - we need to set new page size if a line is added or removed
    int rows = GetRowCount();
    bool ret = TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;

    if ( ret && rows != GetRowCount() )
    {
        const wxRect r = GetPageSize();
        const size_t count = m_pages.Count();
        for ( size_t page = 0; page < count; page++ )
            m_pages[page]->SetSize(r);
    }

    return ret;
}
Exemplo n.º 2
0
void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
{
    wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );

    m_menus[pos]->wxMenuBase::SetTitle(label);

    if ( !IsAttached() )
    {
        return;
    }
    //else: have to modify the existing menu

    int mswpos = MSWPositionForWxMenu(GetMenu(pos),pos);

    UINT_PTR id;
    UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, mswpos, MF_BYPOSITION);
    if ( flagsOld == 0xFFFFFFFF )
    {
        wxLogLastError(wxT("GetMenuState"));

        return;
    }

    if ( flagsOld & MF_POPUP )
    {
        // HIBYTE contains the number of items in the submenu in this case
        flagsOld &= 0xff;
        id = (UINT_PTR)::GetSubMenu((HMENU)m_hMenu, mswpos);
    }
    else
    {
        id = pos;
    }

#ifdef __WXWINCE__
    WinStruct<MENUITEMINFO> info;
    info.fMask = MIIM_TYPE;
    info.fType = MFT_STRING;
    info.cch = label.length();
    info.dwTypeData = wxMSW_CONV_LPTSTR(label);
    if ( !SetMenuItemInfo(GetHmenu(), id, TRUE, &info) )
    {
        wxLogLastError(wxT("SetMenuItemInfo"));
    }

#else
    if ( ::ModifyMenu(GetHmenu(), mswpos, MF_BYPOSITION | MF_STRING | flagsOld,
                      id, label.t_str()) == (int)0xFFFFFFFF )
    {
        wxLogLastError(wxT("ModifyMenu"));
    }
#endif

    Refresh();
}
Exemplo n.º 3
0
void wxToolTip::DoSetTip(WXHWND hWnd)
{
    // update the tip text shown by the control
    wxToolInfo ti((HWND)hWnd, m_id, m_rect);

    // for some reason, changing the tooltip text directly results in
    // repaint of the controls under it, see #10520 -- but this doesn't
    // happen if we reset it first
    ti.lpszText = const_cast<wxChar *>(wxT(""));
    (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);

    ti.lpszText = wxMSW_CONV_LPTSTR(m_text);
    (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);
}
Exemplo n.º 4
0
void wxToolTip::DoAddHWND(WXHWND hWnd)
{
    HWND hwnd = (HWND)hWnd;

    wxToolInfo ti(hwnd, m_id, m_rect);

    // another possibility would be to specify LPSTR_TEXTCALLBACK here as we
    // store the tooltip text ourselves anyhow, and provide it in response to
    // TTN_NEEDTEXT (sent via WM_NOTIFY), but then we would be limited to 79
    // character tooltips as this is the size of the szText buffer in
    // NMTTDISPINFO struct -- and setting the tooltip here we can have tooltips
    // of any length
    ti.hwnd = hwnd;
    ti.lpszText = wxMSW_CONV_LPTSTR(m_text);

    if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) )
    {
        wxLogDebug(wxT("Failed to create the tooltip '%s'"), m_text.c_str());

        return;
    }

#ifdef TTM_SETMAXTIPWIDTH
    if ( !AdjustMaxWidth() )
#endif // TTM_SETMAXTIPWIDTH
    {
        // replace the '\n's with spaces because otherwise they appear as
        // unprintable characters in the tooltip string
        m_text.Replace(wxT("\n"), wxT(" "));
        ti.lpszText = wxMSW_CONV_LPTSTR(m_text);

        if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) )
        {
            wxLogDebug(wxT("Failed to create the tooltip '%s'"), m_text.c_str());
        }
    }
}
Exemplo n.º 5
0
long wxExecute(const wxString& cmd, int flags, wxProcess *handler,
               const wxExecuteEnv *env)
{
    wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );

#if wxUSE_THREADS
    // for many reasons, the code below breaks down if it's called from another
    // thread -- this could be fixed, but as Unix versions don't support this
    // neither I don't want to waste time on this now
    wxASSERT_MSG( wxThread::IsMain(),
                    wxT("wxExecute() can be called only from the main thread") );
#endif // wxUSE_THREADS

    wxString command;

#if wxUSE_IPC
    // DDE hack: this is really not pretty, but we need to allow this for
    // transparent handling of DDE servers in wxMimeTypesManager. Usually it
    // returns the command which should be run to view/open/... a file of the
    // given type. Sometimes, however, this command just launches the server
    // and an additional DDE request must be made to really open the file. To
    // keep all this well hidden from the application, we allow a special form
    // of command: WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND in which
    // case we execute just <command> and process the rest below
    wxString ddeServer, ddeTopic, ddeCommand;
    static const size_t lenDdePrefix = 7;   // strlen("WX_DDE:")
    if ( cmd.Left(lenDdePrefix) == wxT("WX_DDE#") )
    {
        // speed up the concatenations below
        ddeServer.reserve(256);
        ddeTopic.reserve(256);
        ddeCommand.reserve(256);

        const wxChar *p = cmd.c_str() + 7;
#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
        while ( *p && *p != wxT('#') )
        {
            command += *p++;
        }

        if ( *p )
        {
            // skip '#'
            p++;
        }
        else
        {
            wxFAIL_MSG(wxT("invalid WX_DDE command in wxExecute"));
        }

#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
        while ( *p && *p != wxT('#') )
        {
            ddeServer += *p++;
        }

        if ( *p )
        {
            // skip '#'
            p++;
        }
        else
        {
            wxFAIL_MSG(wxT("invalid WX_DDE command in wxExecute"));
        }

#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
        while ( *p && *p != wxT('#') )
        {
            ddeTopic += *p++;
        }

        if ( *p )
        {
            // skip '#'
            p++;
        }
        else
        {
            wxFAIL_MSG(wxT("invalid WX_DDE command in wxExecute"));
        }

#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
        while ( *p )
        {
            ddeCommand += *p++;
        }

        // if we want to just launch the program and not wait for its
        // termination, try to execute DDE command right now, it can succeed if
        // the process is already running - but as it fails if it's not
        // running, suppress any errors it might generate
        if ( !(flags & wxEXEC_SYNC) )
        {
            wxLogNull noErrors;
            if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
            {
                // a dummy PID - this is a hack, of course, but it's well worth
                // it as we don't open a new server each time we're called
                // which would be quite bad
                return -1;
            }
        }
    }
    else
#endif // wxUSE_IPC
    {
        // no DDE
        command = cmd;
    }

    // the IO redirection is only supported with wxUSE_STREAMS
    BOOL redirect = FALSE;

#if wxUSE_STREAMS
    wxPipe pipeIn, pipeOut, pipeErr;

    // open the pipes to which child process IO will be redirected if needed
    if ( handler && handler->IsRedirected() )
    {
        // create pipes for redirecting stdin, stdout and stderr
        if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
        {
            wxLogSysError(_("Failed to redirect the child process IO"));

            // indicate failure: we need to return different error code
            // depending on the sync flag
            return flags & wxEXEC_SYNC ? -1 : 0;
        }

        redirect = TRUE;
    }
#endif // wxUSE_STREAMS

    // create the process
    STARTUPINFO si;
    wxZeroMemory(si);
    si.cb = sizeof(si);

#if wxUSE_STREAMS
    if ( redirect )
    {
        si.dwFlags = STARTF_USESTDHANDLES;

        si.hStdInput = pipeIn[wxPipe::Read];
        si.hStdOutput = pipeOut[wxPipe::Write];
        si.hStdError = pipeErr[wxPipe::Write];

        // We must set the handles to those sides of std* pipes that we won't
        // in the child to be non-inheritable. We must do this before launching
        // the child process as otherwise these handles will be inherited by
        // the child which will never close them and so the pipe will not
        // return ERROR_BROKEN_PIPE if the parent or child exits unexpectedly
        // causing the remaining process to potentially become deadlocked in
        // ReadFile() or WriteFile().
        if ( !::SetHandleInformation(pipeIn[wxPipe::Write],
                                     HANDLE_FLAG_INHERIT, 0) )
            wxLogLastError(wxT("SetHandleInformation(pipeIn)"));

        if ( !::SetHandleInformation(pipeOut[wxPipe::Read],
                                     HANDLE_FLAG_INHERIT, 0) )
            wxLogLastError(wxT("SetHandleInformation(pipeOut)"));

        if ( !::SetHandleInformation(pipeErr[wxPipe::Read],
                                     HANDLE_FLAG_INHERIT, 0) )
            wxLogLastError(wxT("SetHandleInformation(pipeErr)"));
    }
#endif // wxUSE_STREAMS

    // The default logic for showing the console is to show it only if the IO
    // is not redirected however wxEXEC_{SHOW,HIDE}_CONSOLE flags can be
    // explicitly specified to change it.
    if ( (flags & wxEXEC_HIDE_CONSOLE) ||
            (redirect && !(flags & wxEXEC_SHOW_CONSOLE)) )
    {
        si.dwFlags |= STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;
    }


    PROCESS_INFORMATION pi;
    DWORD dwFlags = CREATE_SUSPENDED;

    if ( (flags & wxEXEC_MAKE_GROUP_LEADER) )
        dwFlags |= CREATE_NEW_PROCESS_GROUP;

    dwFlags |= CREATE_DEFAULT_ERROR_MODE ;

    wxWxCharBuffer envBuffer;
    bool useCwd = false;
    if ( env )
    {
        useCwd = !env->cwd.empty();

        // Translate environment variable map into NUL-terminated list of
        // NUL-terminated strings.
        if ( !env->env.empty() )
        {
#if wxUSE_UNICODE
            // Environment variables can contain non-ASCII characters. We could
            // check for it and not use this flag if everything is really ASCII
            // only but there doesn't seem to be any reason to do it so just
            // assume Unicode by default.
            dwFlags |= CREATE_UNICODE_ENVIRONMENT;
#endif // wxUSE_UNICODE

            wxEnvVariableHashMap::const_iterator it;

            size_t envSz = 1; // ending '\0'
#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
            for ( it = env->env.begin(); it != env->env.end(); ++it )
            {
                // Add size of env variable name and value, and '=' char and
                // ending '\0'
                envSz += it->first.length() + it->second.length() + 2;
            }

            envBuffer.extend(envSz);

            wxChar *p = envBuffer.data();
#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
            for ( it = env->env.begin(); it != env->env.end(); ++it )
            {
                const wxString line = it->first + wxS("=") + it->second;

                // Include the trailing NUL which will always terminate the
                // buffer returned by t_str().
                const size_t len = line.length() + 1;

                wxTmemcpy(p, line.t_str(), len);

                p += len;
            }

            // And another NUL to terminate the list of NUL-terminated strings.
            *p = 0;
        }
    }

    // Translate wxWidgets priority to Windows conventions.
    if ( handler )
    {
        unsigned prio = handler->GetPriority();
        if ( prio <= 20 )
            dwFlags |= IDLE_PRIORITY_CLASS;
        else if ( prio <= 40 )
            dwFlags |= BELOW_NORMAL_PRIORITY_CLASS;
        else if ( prio <= 60 )
            dwFlags |= NORMAL_PRIORITY_CLASS;
        else if ( prio <= 80 )
            dwFlags |= ABOVE_NORMAL_PRIORITY_CLASS;
        else if ( prio <= 99 )
            dwFlags |= HIGH_PRIORITY_CLASS;
        else if ( prio <= 100 )
            dwFlags |= REALTIME_PRIORITY_CLASS;
        else
        {
            wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
            dwFlags |= NORMAL_PRIORITY_CLASS;
        }
    }

    bool ok = ::CreateProcess
                (
                 NULL,               // application name (use only cmd line)
                 wxMSW_CONV_LPTSTR(command), // full command line
                 NULL,               // security attributes: defaults for both
                 NULL,               //   the process and its main thread
                 redirect,           // inherit handles if we use pipes
                 dwFlags,            // process creation flags
                 envBuffer.data(),   // environment (may be NULL which is fine)
                 useCwd              // initial working directory
                    ? wxMSW_CONV_LPTSTR(env->cwd)
                    : NULL,          //     (or use the same)
                 &si,                // startup info (unused here)
                 &pi                 // process info
                ) != 0;

#if wxUSE_STREAMS
    // we can close the pipe ends used by child anyhow
    if ( redirect )
    {
        ::CloseHandle(pipeIn.Detach(wxPipe::Read));
        ::CloseHandle(pipeOut.Detach(wxPipe::Write));
        ::CloseHandle(pipeErr.Detach(wxPipe::Write));
    }
#endif // wxUSE_STREAMS

    if ( !ok )
    {
#if wxUSE_STREAMS
        // close the other handles too
        if ( redirect )
        {
            ::CloseHandle(pipeIn.Detach(wxPipe::Write));
            ::CloseHandle(pipeOut.Detach(wxPipe::Read));
            ::CloseHandle(pipeErr.Detach(wxPipe::Read));
        }
#endif // wxUSE_STREAMS

        wxLogSysError(_("Execution of command '%s' failed"), command.c_str());

        return flags & wxEXEC_SYNC ? -1 : 0;
    }

#if wxUSE_STREAMS
    // the input buffer bufOut is connected to stdout, this is why it is
    // called bufOut and not bufIn
    wxStreamTempInputBuffer bufOut,
                            bufErr;

    if ( redirect )
    {
        // We can now initialize the wxStreams
        wxPipeInputStream *
            outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
        wxPipeInputStream *
            errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
        wxPipeOutputStream *
            inStream = new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));

        handler->SetPipeStreams(outStream, inStream, errStream);

        bufOut.Init(outStream);
        bufErr.Init(errStream);
    }
#endif // wxUSE_STREAMS

    // create a hidden window to receive notification about process
    // termination
    HWND hwnd = wxCreateHiddenWindow
                (
                    &gs_classForHiddenWindow,
                    wxMSWEXEC_WNDCLASSNAME,
                    (WNDPROC)wxExecuteWindowCbk
                );

    wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );

    // Alloc data
    wxExecuteData *data = new wxExecuteData;
    data->hProcess    = pi.hProcess;
    data->dwProcessId = pi.dwProcessId;
    data->hWnd        = hwnd;
    data->state       = (flags & wxEXEC_SYNC) != 0;
    if ( flags & wxEXEC_SYNC )
    {
        // handler may be !NULL for capturing program output, but we don't use
        // it wxExecuteData struct in this case
        data->handler = NULL;
    }
    else
    {
        // may be NULL or not
        data->handler = handler;

        if (handler)
            handler->SetPid(pi.dwProcessId);
    }

    DWORD tid;
    HANDLE hThread = ::CreateThread(NULL,
                                    0,
                                    wxExecuteThread,
                                    (void *)data,
                                    0,
                                    &tid);

    // resume process we created now - whether the thread creation succeeded or
    // not
    if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
    {
        // ignore it - what can we do?
        wxLogLastError(wxT("ResumeThread in wxExecute"));
    }

    // close unneeded handle
    if ( !::CloseHandle(pi.hThread) )
    {
        wxLogLastError(wxT("CloseHandle(hThread)"));
    }

    if ( !hThread )
    {
        wxLogLastError(wxT("CreateThread in wxExecute"));

        DestroyWindow(hwnd);
        delete data;

        // the process still started up successfully...
        return pi.dwProcessId;
    }

    gs_asyncThreads.push_back(hThread);
    data->hThread = hThread;

#if wxUSE_IPC
    // second part of DDE hack: now establish the DDE conversation with the
    // just launched process
    if ( !ddeServer.empty() )
    {
        bool ddeOK;

        // give the process the time to init itself
        //
        // we use a very big timeout hoping that WaitForInputIdle() will return
        // much sooner, but not INFINITE just in case the process hangs
        // completely - like this we will regain control sooner or later
        switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
        {
            default:
                wxFAIL_MSG( wxT("unexpected WaitForInputIdle() return code") );
                // fall through

            case WAIT_FAILED:
                wxLogLastError(wxT("WaitForInputIdle() in wxExecute"));

            case WAIT_TIMEOUT:
                wxLogDebug(wxT("Timeout too small in WaitForInputIdle"));

                ddeOK = false;
                break;

            case 0:
                // ok, process ready to accept DDE requests
                ddeOK = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
        }

        if ( !ddeOK )
        {
            wxLogDebug(wxT("Failed to send DDE request to the process \"%s\"."),
                       cmd.c_str());
        }
    }
#endif // wxUSE_IPC

    if ( !(flags & wxEXEC_SYNC) )
    {
        // clean up will be done when the process terminates

        // return the pid
        return pi.dwProcessId;
    }

    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
    wxCHECK_MSG( traits, -1, wxT("no wxAppTraits in wxExecute()?") );

    void *cookie = NULL;
    if ( !(flags & wxEXEC_NODISABLE) )
    {
        // disable all app windows while waiting for the child process to finish
        cookie = traits->BeforeChildWaitLoop();
    }

    // wait until the child process terminates
#if defined(__INTEL_COMPILER) && 1 /* VDM auto patch */
#   pragma ivdep
#   pragma swp
#   pragma unroll
#   pragma prefetch
#   if 0
#       pragma simd noassert
#   endif
#endif /* VDM auto patch */
    while ( data->state )
    {
#if wxUSE_STREAMS
        if ( !bufOut.Update() && !bufErr.Update() )
#endif // wxUSE_STREAMS
        {
            // don't eat 100% of the CPU -- ugly but anything else requires
            // real async IO which we don't have for the moment
            ::Sleep(50);
        }

        // we must always process messages for our hidden window or we'd never
        // get wxWM_PROC_TERMINATED and so this loop would never terminate
        MSG msg;
        ::PeekMessage(&msg, data->hWnd, 0, 0, PM_REMOVE);

        // we may also need to process messages for all the other application
        // windows
        if ( !(flags & wxEXEC_NOEVENTS) )
        {
            wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
            if ( loop )
                loop->Yield();
        }
    }

    if ( !(flags & wxEXEC_NODISABLE) )
    {
        // reenable disabled windows back
        traits->AfterChildWaitLoop(cookie);
    }

    DWORD dwExitCode = data->dwExitCode;
    delete data;

    // return the exit code
    return dwExitCode;
}
Exemplo n.º 6
0
 BOOL Open( const wxString& printerName, LPPRINTER_DEFAULTS pDefault=(LPPRINTER_DEFAULTS)NULL )
 {
     Close();
     return OpenPrinter( wxMSW_CONV_LPTSTR(printerName), &m_hPrinter, pDefault );
 }
Exemplo n.º 7
0
bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data )
{
    WinPrinter printer;
    LPTSTR szPrinterName = wxMSW_CONV_LPTSTR(data.GetPrinterName());

    if (!m_devMode)
        InitializeDevMode(data.GetPrinterName(), &printer);

    HGLOBAL hDevMode = static_cast<HGLOBAL>(m_devMode);

    if ( hDevMode )
    {
        GlobalPtrLock lockDevMode(hDevMode);
        DEVMODE * const devMode = static_cast<DEVMODE *>(lockDevMode.Get());

        //// Orientation
        devMode->dmOrientation = (short)data.GetOrientation();

        //// Collation
        devMode->dmCollate = (data.GetCollate() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE);
        devMode->dmFields |= DM_COLLATE;

        //// Number of copies
        devMode->dmCopies = (short)data.GetNoCopies();
        devMode->dmFields |= DM_COPIES;

        //// Printer name
        wxString name = data.GetPrinterName();
        if (!name.empty())
        {
            // NB: the cast is needed in the ANSI build, strangely enough
            //     dmDeviceName is BYTE[] and not char[] there
            wxStrlcpy(reinterpret_cast<wxChar *>(devMode->dmDeviceName),
                      name.t_str(),
                      WXSIZEOF(devMode->dmDeviceName));
        }

        //// Colour
        if (data.GetColour())
            devMode->dmColor = DMCOLOR_COLOR;
        else
            devMode->dmColor = DMCOLOR_MONOCHROME;
        devMode->dmFields |= DM_COLOR;

        //// Paper size

        // Paper id has priority over paper size. If id is specified, then size
        // is ignored (as it can be filled in even for standard paper sizes)

        wxPrintPaperType *paperType = NULL;

        const wxPaperSize paperId = data.GetPaperId();
        if ( paperId != wxPAPER_NONE && wxThePrintPaperDatabase )
        {
            paperType = wxThePrintPaperDatabase->FindPaperType(paperId);
        }

        if ( paperType )
        {
            devMode->dmPaperSize = (short)paperType->GetPlatformId();
            devMode->dmFields |= DM_PAPERSIZE;
        }
        else // custom (or no) paper size
        {
            const wxSize paperSize = data.GetPaperSize();
            if ( paperSize != wxDefaultSize )
            {
                // Fall back on specifying the paper size explicitly
                if(m_customWindowsPaperId != 0)
                    devMode->dmPaperSize = m_customWindowsPaperId;
                else
                    devMode->dmPaperSize = DMPAPER_USER;
                devMode->dmPaperWidth = (short)(paperSize.x * 10);
                devMode->dmPaperLength = (short)(paperSize.y * 10);
                devMode->dmFields |= DM_PAPERWIDTH;
                devMode->dmFields |= DM_PAPERLENGTH;

                // A printer driver may or may not also want DM_PAPERSIZE to
                // be specified. Also, if the printer driver doesn't implement the DMPAPER_USER
                // size, then this won't work, and even if you found the correct id by
                // enumerating the driver's paper sizes, it probably won't change the actual size,
                // it'll just select that custom paper type with its own current setting.
                // For a discussion on this, see http://www.codeguru.com/forum/showthread.php?threadid=458617
                // Although m_customWindowsPaperId is intended to work around this, it's
                // unclear how it can help you set the custom paper size programmatically.
            }
            //else: neither paper type nor size specified, don't fill DEVMODE
            //      at all so that the system defaults are used
        }

        //// Duplex
        short duplex;
        switch (data.GetDuplex())
        {
            case wxDUPLEX_HORIZONTAL:
                duplex = DMDUP_HORIZONTAL;
                break;
            case wxDUPLEX_VERTICAL:
                duplex = DMDUP_VERTICAL;
                break;
            default:
            // in fact case wxDUPLEX_SIMPLEX:
                duplex = DMDUP_SIMPLEX;
                break;
        }
        devMode->dmDuplex = duplex;
        devMode->dmFields |= DM_DUPLEX;

        //// Quality

        short quality;
        switch (data.GetQuality())
        {
            case wxPRINT_QUALITY_MEDIUM:
                quality = DMRES_MEDIUM;
                break;
            case wxPRINT_QUALITY_LOW:
                quality = DMRES_LOW;
                break;
            case wxPRINT_QUALITY_DRAFT:
                quality = DMRES_DRAFT;
                break;
            case wxPRINT_QUALITY_HIGH:
                quality = DMRES_HIGH;
                break;
            default:
                quality = (short)data.GetQuality();
                devMode->dmYResolution = quality;
                devMode->dmFields |= DM_YRESOLUTION;
                break;
        }
        devMode->dmPrintQuality = quality;
        devMode->dmFields |= DM_PRINTQUALITY;

        if (data.GetPrivDataLen() > 0)
        {
            memcpy( (char *)devMode+devMode->dmSize, data.GetPrivData(), data.GetPrivDataLen() );
            devMode->dmDriverExtra = (WXWORD)data.GetPrivDataLen();
        }

        if (data.GetBin() != wxPRINTBIN_DEFAULT)
        {
            switch (data.GetBin())
            {
                case wxPRINTBIN_ONLYONE:        devMode->dmDefaultSource = DMBIN_ONLYONE;       break;
                case wxPRINTBIN_LOWER:          devMode->dmDefaultSource = DMBIN_LOWER;         break;
                case wxPRINTBIN_MIDDLE:         devMode->dmDefaultSource = DMBIN_MIDDLE;        break;
                case wxPRINTBIN_MANUAL:         devMode->dmDefaultSource = DMBIN_MANUAL;        break;
                case wxPRINTBIN_ENVELOPE:       devMode->dmDefaultSource = DMBIN_ENVELOPE;      break;
                case wxPRINTBIN_ENVMANUAL:      devMode->dmDefaultSource = DMBIN_ENVMANUAL;     break;
                case wxPRINTBIN_AUTO:           devMode->dmDefaultSource = DMBIN_AUTO;          break;
                case wxPRINTBIN_TRACTOR:        devMode->dmDefaultSource = DMBIN_TRACTOR;       break;
                case wxPRINTBIN_SMALLFMT:       devMode->dmDefaultSource = DMBIN_SMALLFMT;      break;
                case wxPRINTBIN_LARGEFMT:       devMode->dmDefaultSource = DMBIN_LARGEFMT;      break;
                case wxPRINTBIN_LARGECAPACITY:  devMode->dmDefaultSource = DMBIN_LARGECAPACITY; break;
                case wxPRINTBIN_CASSETTE:       devMode->dmDefaultSource = DMBIN_CASSETTE;      break;
                case wxPRINTBIN_FORMSOURCE:     devMode->dmDefaultSource = DMBIN_FORMSOURCE;    break;

                default:
                    devMode->dmDefaultSource = (short)(DMBIN_USER + data.GetBin() - wxPRINTBIN_USER); // 256 + data.GetBin() - 14 = 242 + data.GetBin()
                    break;
            }

            devMode->dmFields |= DM_DEFAULTSOURCE;
        }
        if (data.GetMedia() != wxPRINTMEDIA_DEFAULT)
        {
            devMode->dmMediaType = data.GetMedia();
            devMode->dmFields |= DM_MEDIATYPE;
        }

        if( printer )
        {
            // Step 3:
            // Merge the new settings with the old.
            // This gives the driver an opportunity to update any private
            // portions of the DevMode structure.
            DocumentProperties( NULL,
                printer,
                szPrinterName,
                (LPDEVMODE)hDevMode, // Reuse our buffer for output.
                (LPDEVMODE)hDevMode, // Pass the driver our changes
                DM_IN_BUFFER |       // Commands to Merge our changes and
                DM_OUT_BUFFER );     // write the result.
        }
    }

    if ( m_devNames )
    {
        ::GlobalFree(static_cast<HGLOBAL>(m_devNames));
    }

    // TODO: I hope it's OK to pass some empty strings to DEVNAMES.
    m_devNames = wxCreateDevNames(wxEmptyString, data.GetPrinterName(), wxEmptyString);

    return true;
}
Exemplo n.º 8
0
void wxWindowsPrintNativeData::InitializeDevMode(const wxString& printerName, WinPrinter* printer)
{
    if (m_devMode)
        return;

    LPTSTR szPrinterName = wxMSW_CONV_LPTSTR(printerName);

    // From MSDN: How To Modify Printer Settings with the DocumentProperties() Function
    // The purpose of this is to fill the DEVMODE with privdata from printer driver.
    // If we have a printer name and OpenPrinter successfully returns
    // this replaces the PrintDlg function which creates the DEVMODE filled only with data from default printer.
    if ( !m_devMode && !printerName.IsEmpty() )
    {
        // Open printer
        if ( printer && printer->Open( printerName ) == TRUE )
        {
            DWORD dwNeeded, dwRet;

            // Step 1:
            // Allocate a buffer of the correct size.
            dwNeeded = DocumentProperties( NULL,
                *printer,        // Handle to our printer.
                szPrinterName,   // Name of the printer.
                NULL,            // Asking for size, so
                NULL,            // these are not used.
                0 );             // Zero returns buffer size.

            LPDEVMODE tempDevMode = static_cast<LPDEVMODE>( GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, dwNeeded ) );

            // Step 2:
            // Get the default DevMode for the printer
            dwRet = DocumentProperties( NULL,
                *printer,
                szPrinterName,
                tempDevMode,     // The address of the buffer to fill.
                NULL,            // Not using the input buffer.
                DM_OUT_BUFFER ); // Have the output buffer filled.

            if ( dwRet != IDOK )
            {
                // If failure, cleanup
                GlobalFree( tempDevMode );
                printer->Close();
            }
            else
            {
                m_devMode = tempDevMode;
                tempDevMode = NULL;
            }
        }
    }

    if ( !m_devMode )
    {
        // Use PRINTDLG as a way of creating a DEVMODE object
        PRINTDLG pd;

        memset(&pd, 0, sizeof(PRINTDLG));
#ifdef __WXWINCE__
        pd.cbStruct    = sizeof(PRINTDLG);
#else
        pd.lStructSize    = sizeof(PRINTDLG);
#endif

        pd.hwndOwner      = NULL;
        pd.hDevMode       = NULL; // Will be created by PrintDlg
        pd.hDevNames      = NULL; // Ditto

        pd.Flags          = PD_RETURNDEFAULT;
        pd.nCopies        = 1;

        // Fill out the DEVMODE structure
        // so we can use it as input in the 'real' PrintDlg
        if (!PrintDlg(&pd))
        {
            if ( pd.hDevMode )
                GlobalFree(pd.hDevMode);
            if ( pd.hDevNames )
                GlobalFree(pd.hDevNames);
            pd.hDevMode = NULL;
            pd.hDevNames = NULL;

#if wxDEBUG_LEVEL
            wxLogDebug(wxT("Printing error: ") + wxGetPrintDlgError());
#endif // wxDEBUG_LEVEL
        }
        else
        {
            m_devMode = pd.hDevMode;
            pd.hDevMode = NULL;

            // We'll create a new DEVNAMEs structure below.
            if ( pd.hDevNames )
                GlobalFree(pd.hDevNames);
            pd.hDevNames = NULL;

            // hDevNames = pd->hDevNames;
            // m_devNames = (void*)(long) hDevNames;
            // pd->hDevnames = NULL;

        }
    }

}
Exemplo n.º 9
0
// same as AddPage() but does it at given position
bool wxNotebook::InsertPage(size_t nPage,
                            wxNotebookPage *pPage,
                            const wxString& strText,
                            bool bSelect,
                            int imageId)
{
    wxCHECK_MSG( pPage != NULL, false, wxT("NULL page in wxNotebook::InsertPage") );
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
                 wxT("invalid index in wxNotebook::InsertPage") );

    wxASSERT_MSG( pPage->GetParent() == this,
                    wxT("notebook pages must have notebook as parent") );

    // add a new tab to the control
    // ----------------------------

    // init all fields to 0
    TC_ITEM tcItem;
    wxZeroMemory(tcItem);

    // set the image, if any
    if ( imageId != -1 )
    {
        tcItem.mask |= TCIF_IMAGE;
        tcItem.iImage  = imageId;
    }

    // and the text
    if ( !strText.empty() )
    {
        tcItem.mask |= TCIF_TEXT;
        tcItem.pszText = wxMSW_CONV_LPTSTR(strText);
    }

    // hide the page: unless it is selected, it shouldn't be shown (and if it
    // is selected it will be shown later)
    HWND hwnd = GetWinHwnd(pPage);
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);

    // this updates internal flag too -- otherwise it would get out of sync
    // with the real state
    pPage->Show(false);


    // fit the notebook page to the tab control's display area: this should be
    // done before adding it to the notebook or TabCtrl_InsertItem() will
    // change the notebooks size itself!
    AdjustPageSize(pPage);

    // finally do insert it
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
    {
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());

        return false;
    }

    // need to update the bg brush when the first page is added
    // so the first panel gets the correct themed background
    if ( m_pages.empty() )
    {
#if wxUSE_UXTHEME
        UpdateBgBrush();
#endif // wxUSE_UXTHEME
    }

    // succeeded: save the pointer to the page
    m_pages.Insert(pPage, nPage);

    // we may need to adjust the size again if the notebook size changed:
    // normally this only happens for the first page we add (the tabs which
    // hadn't been there before are now shown) but for a multiline notebook it
    // can happen for any page at all as a new row could have been started
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
    {
        AdjustPageSize(pPage);

        // Additionally, force the layout of the notebook itself by posting a
        // size event to it. If we don't do it, notebooks with pages on the
        // left or the right side may fail to account for the fact that they
        // are now big enough to fit all all of their pages on one row and
        // still reserve space for the second row of tabs, see #1792.
        const wxSize s = GetSize();
        ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(s.x, s.y));
    }

    // now deal with the selection
    // ---------------------------

    // if the inserted page is before the selected one, we must update the
    // index of the selected page
    if ( int(nPage) <= m_selection )
    {
        // one extra page added
        m_selection++;
    }

    DoSetSelectionAfterInsertion(nPage, bSelect);

    InvalidateBestSize();

    return true;
}
Exemplo n.º 10
0
void wxMenuItem::SetItemLabel(const wxString& txt)
{
    wxString text = txt;

    // don't do anything if label didn't change
    if ( m_text == txt )
        return;

    // wxMenuItemBase will do stock ID checks
    wxMenuItemBase::SetItemLabel(text);

    // the item can be not attached to any menu yet and SetItemLabel() is still
    // valid to call in this case and should do nothing else
    if ( !m_parentMenu )
        return;

#if wxUSE_ACCEL
    m_parentMenu->UpdateAccel(this);
#endif // wxUSE_ACCEL

    const int itemPos = MSGetMenuItemPos();
    if ( itemPos == -1 )
        return;

    HMENU hMenu = GetHMenuOf(m_parentMenu);

    // update the text of the native menu item
    WinStruct<MENUITEMINFO> info;

    // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't
    // work as it resets the menu bitmap, so we need to first get the old item
    // state and then modify it
    const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95;
    info.fMask = MIIM_STATE |
                 MIIM_ID |
                 MIIM_SUBMENU |
                 MIIM_CHECKMARKS |
                 MIIM_DATA;
    if ( isLaterThanWin95 )
        info.fMask |= MIIM_BITMAP | MIIM_FTYPE;
    else
        info.fMask |= MIIM_TYPE;
    if ( !::GetMenuItemInfo(hMenu, itemPos, TRUE, &info) )
    {
        wxLogLastError(wxT("GetMenuItemInfo"));
        return;
    }

#if wxUSE_OWNER_DRAWN
    // Don't set the text for the owner drawn items, they don't use it and even
    // though setting it doesn't seem to actually do any harm under Windows 7,
    // avoid doing this relatively nonsensical operation just in case it does
    // break something on other, past or future, Windows versions.
    //
    // Notice that we do need to call SetMenuItemInfo() even for the ownerdrawn
    // items however as otherwise their size wouldn't be recalculated as
    // WM_MEASUREITEM wouldn't be sent and this could result in display
    // problems if the length of the menu item changed significantly.
    //
    // Also notice that we shouldn't use our IsOwnerDrawn() because it can be
    // true because it was set by e.g. SetBitmap(), even if the item wasn't
    // made owner drawn at Windows level.
    if ( !(info.fState & MF_OWNERDRAW) )
#endif // wxUSE_OWNER_DRAWN
    {
        if ( isLaterThanWin95 )
            info.fMask |= MIIM_STRING;
        //else: MIIM_TYPE already specified
        info.dwTypeData = wxMSW_CONV_LPTSTR(m_text);
        info.cch = m_text.length();
    }

    if ( !::SetMenuItemInfo(hMenu, itemPos, TRUE, &info) )
    {
        wxLogLastError(wxT("SetMenuItemInfo"));
    }
}
Exemplo n.º 11
0
void wxMenu::SetTitle(const wxString& label)
{
    bool hasNoTitle = m_title.empty();
    m_title = label;

    HMENU hMenu = GetHmenu();

    if ( hasNoTitle )
    {
        if ( !label.empty() )
        {
            if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
                               (UINT_PTR)idMenuTitle, m_title.t_str()) ||
                 !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
            {
                wxLogLastError(wxT("InsertMenu"));
            }
        }
    }
    else
    {
        if ( label.empty() )
        {
            // remove the title and the separator after it
            if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
                 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
            {
                wxLogLastError(wxT("RemoveMenu"));
            }
        }
        else
        {
            // modify the title
#ifdef __WXWINCE__
            WinStruct<MENUITEMINFO> info;
            info.fMask = MIIM_TYPE;
            info.fType = MFT_STRING;
            info.cch = m_title.length();
            info.dwTypeData = wxMSW_CONV_LPTSTR(m_title);
            if ( !SetMenuItemInfo(hMenu, 0, TRUE, & info) )
            {
                wxLogLastError(wxT("SetMenuItemInfo"));
            }
#else
            if ( !ModifyMenu(hMenu, 0u,
                             MF_BYPOSITION | MF_STRING,
                             (UINT_PTR)idMenuTitle, m_title.t_str()) )
            {
                wxLogLastError(wxT("ModifyMenu"));
            }
#endif
        }
    }

#ifdef __WIN32__
    // put the title string in bold face
    if ( !m_title.empty() )
    {
        SetDefaultMenuItem(GetHmenu(), (UINT)idMenuTitle);
    }
#endif // Win32
}
Exemplo n.º 12
0
// append a new item or submenu to the menu
bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
{
#if wxUSE_ACCEL
    UpdateAccel(pItem);
#endif // wxUSE_ACCEL

    // we should support disabling the item even prior to adding it to the menu
    UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED;

    // if "Break" has just been called, insert a menu break before this item
    // (and don't forget to reset the flag)
    if ( m_doBreak ) {
        flags |= MF_MENUBREAK;
        m_doBreak = false;
    }

    if ( pItem->IsSeparator() ) {
        flags |= MF_SEPARATOR;
    }

    // id is the numeric id for normal menu items and HMENU for submenus as
    // required by ::AppendMenu() API
    UINT_PTR id;
    wxMenu *submenu = pItem->GetSubMenu();
    if ( submenu != NULL ) {
        wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );

        submenu->SetParent(this);

        id = (UINT_PTR)submenu->GetHMenu();

        flags |= MF_POPUP;
    }
    else {
        id = pItem->GetMSWId();
    }


    // prepare to insert the item in the menu
    wxString itemText = pItem->GetItemLabel();
    LPCTSTR pData = NULL;
    if ( pos == (size_t)-1 )
    {
        // append at the end (note that the item is already appended to
        // internal data structures)
        pos = GetMenuItemCount() - 1;
    }

    // Update radio groups data if we're inserting a new radio item.
    //
    // NB: If we supported inserting non-radio items in the middle of existing
    //     radio groups to break them into two subgroups, we'd need to update
    //     m_radioData in this case too but currently this is not supported.
    bool checkInitially = false;
    if ( pItem->GetKind() == wxITEM_RADIO )
    {
        if ( !m_radioData )
            m_radioData = new wxMenuRadioItemsData;

        if ( m_radioData->UpdateOnInsert(pos) )
            checkInitially = true;
    }

    // adjust position to account for the title of a popup menu, if any
    if ( !GetMenuBar() && !m_title.empty() )
        pos += 2; // for the title itself and its separator

    BOOL ok = false;

#if wxUSE_OWNER_DRAWN
    // Under older systems mixing owner-drawn and non-owner-drawn items results
    // in inconsistent margins, so we force this one to be owner-drawn if any
    // other items already are.
    if ( m_ownerDrawn )
        pItem->SetOwnerDrawn(true);
#endif // wxUSE_OWNER_DRAWN

    // check if we have something more than a simple text item
#if wxUSE_OWNER_DRAWN
    bool makeItemOwnerDrawn = false;
    if ( pItem->IsOwnerDrawn() )
    {
#ifndef __DMC__

        if ( !m_ownerDrawn && !pItem->IsSeparator() )
        {
            // MIIM_BITMAP only works under WinME/2000+ so we always use owner
            // drawn item under the previous versions and we also have to use
            // them in any case if the item has custom colours or font
            static const wxWinVersion winver = wxGetWinVersion();
            bool mustUseOwnerDrawn = winver < wxWinVersion_98 ||
                                     pItem->GetTextColour().IsOk() ||
                                     pItem->GetBackgroundColour().IsOk() ||
                                     pItem->GetFont().IsOk();

            if ( !mustUseOwnerDrawn )
            {
                const wxBitmap& bmpUnchecked = pItem->GetBitmap(false),
                                bmpChecked   = pItem->GetBitmap(true);

                if ( (bmpUnchecked.IsOk() && IsGreaterThanStdSize(bmpUnchecked)) ||
                     (bmpChecked.IsOk()   && IsGreaterThanStdSize(bmpChecked)) )
                {
                    mustUseOwnerDrawn = true;
                }
            }

            // use InsertMenuItem() if possible as it's guaranteed to look
            // correct while our owner-drawn code is not
            if ( !mustUseOwnerDrawn )
            {
                WinStruct<MENUITEMINFO> mii;
                mii.fMask = MIIM_STRING | MIIM_DATA;

                // don't set hbmpItem for the checkable items as it would
                // be used for both checked and unchecked state
                if ( pItem->IsCheckable() )
                {
                    mii.fMask |= MIIM_CHECKMARKS;
                    mii.hbmpChecked = GetHBitmapForMenu(pItem, true);
                    mii.hbmpUnchecked = GetHBitmapForMenu(pItem, false);
                }
                else if ( pItem->GetBitmap().IsOk() )
                {
                    mii.fMask |= MIIM_BITMAP;
                    mii.hbmpItem = GetHBitmapForMenu(pItem);
                }

                mii.cch = itemText.length();
                mii.dwTypeData = wxMSW_CONV_LPTSTR(itemText);

                if ( flags & MF_POPUP )
                {
                    mii.fMask |= MIIM_SUBMENU;
                    mii.hSubMenu = GetHmenuOf(pItem->GetSubMenu());
                }
                else
                {
                    mii.fMask |= MIIM_ID;
                    mii.wID = id;
                }

                mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem);

                ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii);
                if ( !ok )
                {
                    wxLogLastError(wxT("InsertMenuItem()"));
                }
                else // InsertMenuItem() ok
                {
                    // we need to remove the extra indent which is reserved for
                    // the checkboxes by default as it looks ugly unless check
                    // boxes are used together with bitmaps and this is not the
                    // case in wx API
                    WinStruct<MENUINFO> mi;

                    // don't call SetMenuInfo() directly, this would prevent
                    // the app from starting up under Windows 95/NT 4
                    typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *);

                    wxDynamicLibrary dllUser(wxT("user32"));
                    wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser);
                    if ( pfnSetMenuInfo )
                    {
                        mi.fMask = MIM_STYLE;
                        mi.dwStyle = MNS_CHECKORBMP;
                        if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) )
                        {
                            wxLogLastError(wxT("SetMenuInfo(MNS_NOCHECK)"));
                        }
                    }

                    // tell the item that it's not really owner-drawn but only
                    // needs to draw its bitmap, the rest is done by Windows
                    pItem->SetOwnerDrawn(false);
                }
            }
        }
#endif // __DMC__

        if ( !ok )
        {
            // item draws itself, pass pointer to it in data parameter
            flags |= MF_OWNERDRAW;
            pData = (LPCTSTR)pItem;

            bool updateAllMargins = false;

            // get size of bitmap always return valid value (0 for invalid bitmap),
            // so we don't needed check if bitmap is valid ;)
            int uncheckedW = pItem->GetBitmap(false).GetWidth();
            int checkedW   = pItem->GetBitmap(true).GetWidth();

            if ( m_maxBitmapWidth < uncheckedW )
            {
                m_maxBitmapWidth = uncheckedW;
                updateAllMargins = true;
            }

            if ( m_maxBitmapWidth < checkedW )
            {
                m_maxBitmapWidth = checkedW;
                updateAllMargins = true;
            }

            // make other item ownerdrawn and update margin width for equals alignment
            if ( !m_ownerDrawn || updateAllMargins )
            {
                // we must use position in SetOwnerDrawnMenuItem because
                // all separators have the same id
                int pos = 0;
                wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
                while (node)
                {
                    wxMenuItem* item = node->GetData();

                    if ( !item->IsOwnerDrawn())
                    {
                        item->SetOwnerDrawn(true);
                        SetOwnerDrawnMenuItem(GetHmenu(), pos,
                                              reinterpret_cast<ULONG_PTR>(item), TRUE);
                    }

                    item->SetMarginWidth(m_maxBitmapWidth);

                    node = node->GetNext();
                    pos++;
                }

                // set menu as ownerdrawn
                m_ownerDrawn = true;

                // also ensure that the new item itself is made owner drawn
                makeItemOwnerDrawn = true;

                ResetMaxAccelWidth();
            }
            // only update our margin for equals alignment to other item
            else if ( !updateAllMargins )
            {
                pItem->SetMarginWidth(m_maxBitmapWidth);
            }
        }
    }
    else
#endif // wxUSE_OWNER_DRAWN
    {
        // item is just a normal string (passed in data parameter)
        flags |= MF_STRING;

#ifdef __WXWINCE__
        itemText = wxMenuItem::GetLabelText(itemText);
#endif

        pData = itemText.t_str();
    }

    // item might have already been inserted by InsertMenuItem() above
    if ( !ok )
    {
        if ( !::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData) )
        {
            wxLogLastError(wxT("InsertMenu[Item]()"));

            return false;
        }

        if ( makeItemOwnerDrawn )
        {
            SetOwnerDrawnMenuItem(GetHmenu(), pos,
                                  reinterpret_cast<ULONG_PTR>(pItem), TRUE);
        }
    }


    // Check the item if it should be initially checked.
    if ( checkInitially )
        pItem->Check(true);

    // if we just appended the title, highlight it
    if ( id == (UINT_PTR)idMenuTitle )
    {
        // visually select the menu title
        SetDefaultMenuItem(GetHmenu(), id);
    }

    // if we're already attached to the menubar, we must update it
    if ( IsAttached() && GetMenuBar()->IsAttached() )
    {
        GetMenuBar()->Refresh();
    }

    return true;
}
Exemplo n.º 13
0
void wxToolTip::DoAddHWND(WXHWND hWnd)
{
    HWND hwnd = (HWND)hWnd;

    wxToolInfo ti(hwnd, m_id, m_rect);

    // another possibility would be to specify LPSTR_TEXTCALLBACK here as we
    // store the tooltip text ourselves anyhow, and provide it in response to
    // TTN_NEEDTEXT (sent via WM_NOTIFY), but then we would be limited to 79
    // character tooltips as this is the size of the szText buffer in
    // NMTTDISPINFO struct -- and setting the tooltip here we can have tooltips
    // of any length
    ti.hwnd = hwnd;
    ti.lpszText = wxMSW_CONV_LPTSTR(m_text);

    if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) )
    {
        wxLogDebug(wxT("Failed to create the tooltip '%s'"), m_text.c_str());

        return;
    }

#ifdef TTM_SETMAXTIPWIDTH
    if ( wxApp::GetComCtl32Version() >= 470 )
    {
        // use TTM_SETMAXTIPWIDTH to make tooltip multiline using the
        // extent of its first line as max value
        HFONT hfont = (HFONT)
            SendTooltipMessage(GetToolTipCtrl(), WM_GETFONT, 0);

        if ( !hfont )
        {
            hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
            if ( !hfont )
            {
                wxLogLastError(wxT("GetStockObject(DEFAULT_GUI_FONT)"));
            }
        }

        MemoryHDC hdc;
        if ( !hdc )
        {
            wxLogLastError(wxT("CreateCompatibleDC(NULL)"));
        }

        if ( !SelectObject(hdc, hfont) )
        {
            wxLogLastError(wxT("SelectObject(hfont)"));
        }

        // find the width of the widest line
        int maxWidth = 0;
        wxStringTokenizer tokenizer(m_text, wxT("\n"));
        while ( tokenizer.HasMoreTokens() )
        {
            const wxString token = tokenizer.GetNextToken();

            SIZE sz;
            if ( !::GetTextExtentPoint32(hdc, token.t_str(),
                                         token.length(), &sz) )
            {
                wxLogLastError(wxT("GetTextExtentPoint32"));
            }

            if ( sz.cx > maxWidth )
                maxWidth = sz.cx;
        }

        // limit size to ms_maxWidth, if set
        if ( ms_maxWidth == 0 )
        {
            // this is more or less arbitrary but seems to work well
            static const int DEFAULT_MAX_WIDTH = 400;

            ms_maxWidth = wxGetClientDisplayRect().width / 2;

            if ( ms_maxWidth > DEFAULT_MAX_WIDTH )
                ms_maxWidth = DEFAULT_MAX_WIDTH;
        }

        if ( ms_maxWidth != -1 && maxWidth > ms_maxWidth )
            maxWidth = ms_maxWidth;

        // only set a new width if it is bigger than the current setting:
        // otherwise adding a tooltip with shorter line(s) than a previous
        // one would result in breaking the longer lines unnecessarily as
        // all our tooltips share the same maximal width
        if ( maxWidth > SendTooltipMessage(GetToolTipCtrl(),
                                           TTM_GETMAXTIPWIDTH, 0) )
        {
            SendTooltipMessage(GetToolTipCtrl(), TTM_SETMAXTIPWIDTH,
                               wxUIntToPtr(maxWidth));
        }
    }
    else
#endif // TTM_SETMAXTIPWIDTH
    {
        // replace the '\n's with spaces because otherwise they appear as
        // unprintable characters in the tooltip string
        m_text.Replace(wxT("\n"), wxT(" "));
        ti.lpszText = wxMSW_CONV_LPTSTR(m_text);

        if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) )
        {
            wxLogDebug(wxT("Failed to create the tooltip '%s'"), m_text.c_str());
        }
    }
}
Exemplo n.º 14
0
// append a new item or submenu to the menu
bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
{
#if wxUSE_ACCEL
    UpdateAccel(pItem);
#endif // wxUSE_ACCEL

    // we should support disabling the item even prior to adding it to the menu
    UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED;

    // if "Break" has just been called, insert a menu break before this item
    // (and don't forget to reset the flag)
    if ( m_doBreak ) {
        flags |= MF_MENUBREAK;
        m_doBreak = false;
    }

    if ( pItem->IsSeparator() ) {
        flags |= MF_SEPARATOR;
    }

    // id is the numeric id for normal menu items and HMENU for submenus as
    // required by ::AppendMenu() API
    UINT_PTR id;
    wxMenu *submenu = pItem->GetSubMenu();
    if ( submenu != NULL ) {
        wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );

        submenu->SetParent(this);

        id = (UINT_PTR)submenu->GetHMenu();

        flags |= MF_POPUP;
    }
    else {
        id = pItem->GetMSWId();
    }


    // prepare to insert the item in the menu
    wxString itemText = pItem->GetItemLabel();
    LPCTSTR pData = NULL;
    if ( pos == (size_t)-1 )
    {
        // append at the end (note that the item is already appended to
        // internal data structures)
        pos = GetMenuItemCount() - 1;
    }

    // Update radio groups data if we're inserting a new menu item.
    // Inserting radio and non-radio item has a different impact
    // on radio groups so we have to handle each case separately.
    // (Inserting a radio item in the middle of existing group extends
    // the group, but inserting non-radio item breaks it into two subgroups.)
    //
    bool checkInitially = false;
    if ( pItem->IsRadio() )
    {
        if ( !m_radioData )
            m_radioData = new wxMenuRadioItemsData;

        if ( m_radioData->UpdateOnInsertRadio(pos) )
            checkInitially = true;
    }
    else if ( m_radioData )
    {
        if ( m_radioData->UpdateOnInsertNonRadio(pos) )
        {
            // One of the existing groups has been split into two subgroups.
            wxFAIL_MSG(wxS("Inserting non-radio item inside a radio group?"));
        }
    }

    // Also handle the case of check menu items that had been checked before
    // being attached to the menu: we don't need to actually call Check() on
    // them, so we don't use checkInitially in this case, but we do need to
    // make them checked at Windows level too. Notice that we shouldn't ask
    // Windows for the checked state here, as wxMenuItem::IsChecked() does, as
    // the item is not attached yet, so explicitly call the base class version.
    if ( pItem->IsCheck() && pItem->wxMenuItemBase::IsChecked() )
        flags |= MF_CHECKED;

    // adjust position to account for the title of a popup menu, if any
    if ( !GetMenuBar() && !m_title.empty() )
        pos += 2; // for the title itself and its separator

    BOOL ok = false;

#if wxUSE_OWNER_DRAWN
    // Under older systems mixing owner-drawn and non-owner-drawn items results
    // in inconsistent margins, so we force this one to be owner-drawn if any
    // other items already are.
    if ( m_ownerDrawn )
        pItem->SetOwnerDrawn(true);

    // check if we have something more than a simple text item
    bool makeItemOwnerDrawn = false;
#endif // wxUSE_OWNER_DRAWN

    if (
#if wxUSE_OWNER_DRAWN
            !pItem->IsOwnerDrawn() &&
#endif
        !pItem->IsSeparator() )
            {
                WinStruct<MENUITEMINFO> mii;
                mii.fMask = MIIM_STRING | MIIM_DATA;

                // don't set hbmpItem for the checkable items as it would
                // be used for both checked and unchecked state
                if ( pItem->IsCheckable() )
                {
                    mii.fMask |= MIIM_CHECKMARKS;
                    mii.hbmpChecked = pItem->GetHBitmapForMenu(wxMenuItem::Checked);
                    mii.hbmpUnchecked = pItem->GetHBitmapForMenu(wxMenuItem::Unchecked);
                }
                else if ( pItem->GetBitmap().IsOk() )
                {
                    mii.fMask |= MIIM_BITMAP;
                    mii.hbmpItem = pItem->GetHBitmapForMenu(wxMenuItem::Normal);
                }

                mii.cch = itemText.length();
                mii.dwTypeData = wxMSW_CONV_LPTSTR(itemText);

                if ( flags & MF_POPUP )
                {
                    mii.fMask |= MIIM_SUBMENU;
                    mii.hSubMenu = GetHmenuOf(pItem->GetSubMenu());
                }
                else
                {
                    mii.fMask |= MIIM_ID;
                    mii.wID = id;
                }

                if ( flags & MF_GRAYED )
                {
                    mii.fMask |= MIIM_STATE;
                    mii.fState = MFS_GRAYED;
                }

                if ( flags & MF_CHECKED )
                {
                    mii.fMask |= MIIM_STATE;
                    mii.fState = MFS_CHECKED;
                }

                mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem);

                ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii);
                if ( !ok )
                {
                    wxLogLastError(wxT("InsertMenuItem()"));
#if wxUSE_OWNER_DRAWN
            // In case of failure switch new item to the owner-drawn mode.
            makeItemOwnerDrawn = true;
#endif
                }
                else // InsertMenuItem() ok
                {
                    // we need to remove the extra indent which is reserved for
                    // the checkboxes by default as it looks ugly unless check
                    // boxes are used together with bitmaps and this is not the
                    // case in wx API
                    WinStruct<MENUINFO> mi;
                    mi.fMask = MIM_STYLE;
                    mi.dwStyle = MNS_CHECKORBMP;
                    if ( !::SetMenuInfo(GetHmenu(), &mi) )
                    {
                        wxLogLastError(wxT("SetMenuInfo(MNS_NOCHECK)"));
                    }
                }
        }

#if wxUSE_OWNER_DRAWN
    if ( pItem->IsOwnerDrawn() || makeItemOwnerDrawn )
        {
            // item draws itself, pass pointer to it in data parameter
            flags |= MF_OWNERDRAW;
            pData = (LPCTSTR)pItem;

            bool updateAllMargins = false;

            // get size of bitmap always return valid value (0 for invalid bitmap),
            // so we don't needed check if bitmap is valid ;)
            int uncheckedW = pItem->GetBitmap(false).GetWidth();
            int checkedW   = pItem->GetBitmap(true).GetWidth();

            if ( m_maxBitmapWidth < uncheckedW )
            {
                m_maxBitmapWidth = uncheckedW;
                updateAllMargins = true;
            }

            if ( m_maxBitmapWidth < checkedW )
            {
                m_maxBitmapWidth = checkedW;
                updateAllMargins = true;
            }

            // make other item ownerdrawn and update margin width for equals alignment
            if ( !m_ownerDrawn || updateAllMargins )
            {
                // we must use position in SetOwnerDrawnMenuItem because
                // all separators have the same id
                int position = 0;
                wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
                while (node)
                {
                    wxMenuItem* item = node->GetData();

                    // Current item is already added to the list of items
                    // but is not yet physically attached to the menu
                    // so we have to skip setting it as an owner drawn.
                    // It will be done later on when the item will be created.
                    if ( !item->IsOwnerDrawn() && item != pItem )
                    {
                        item->SetOwnerDrawn(true);
                        SetOwnerDrawnMenuItem(GetHmenu(), position,
                                              reinterpret_cast<ULONG_PTR>(item), TRUE);
                    }

                    item->SetMarginWidth(m_maxBitmapWidth);

                    node = node->GetNext();
                    // Current item is already added to the list of items
                    // but is not yet physically attached to the menu
                    // so it cannot be counted while determining position
                    // in the menu.
                    if ( item != pItem )
                        position++;
                }

                // set menu as ownerdrawn
                m_ownerDrawn = true;

                ResetMaxAccelWidth();
            }
            // only update our margin for equals alignment to other item
            else if ( !updateAllMargins )
            {
                pItem->SetMarginWidth(m_maxBitmapWidth);
            }
        }
#endif // wxUSE_OWNER_DRAWN

    // item might have already been inserted by InsertMenuItem() above
    if ( !ok )
    {
        if ( !::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData) )
        {
            wxLogLastError(wxT("InsertMenu[Item]()"));

            return false;
        }

#if wxUSE_OWNER_DRAWN
        if ( makeItemOwnerDrawn )
        {
            pItem->SetOwnerDrawn(true);
            SetOwnerDrawnMenuItem(GetHmenu(), pos,
                                  reinterpret_cast<ULONG_PTR>(pItem), TRUE);
        }
#endif
    }


    // Check the item if it should be initially checked.
    if ( checkInitially )
        pItem->Check(true);

    // if we just appended the title, highlight it
    if ( id == (UINT_PTR)idMenuTitle )
    {
        // visually select the menu title
        SetDefaultMenuItem(GetHmenu(), id);
    }

    // if we're already attached to the menubar, we must update it
    if ( IsAttached() && GetMenuBar()->IsAttached() )
    {
        GetMenuBar()->Refresh();
    }

    return true;
}
Exemplo n.º 15
0
void wxMenuItem::SetItemLabel(const wxString& txt)
{
    wxString text = txt;

    // don't do anything if label didn't change
    if ( m_text == txt )
        return;

    // wxMenuItemBase will do stock ID checks
    wxMenuItemBase::SetItemLabel(text);

    // the item can be not attached to any menu yet and SetItemLabel() is still
    // valid to call in this case and should do nothing else
    if ( !m_parentMenu )
        return;

#if wxUSE_ACCEL
    m_parentMenu->UpdateAccel(this);
#endif // wxUSE_ACCEL

    const UINT id = GetMSWId();
    HMENU hMenu = GetHMenuOf(m_parentMenu);
    if ( !hMenu || ::GetMenuState(hMenu, id, MF_BYCOMMAND) == (UINT)-1 )
        return;

#if wxUSE_OWNER_DRAWN
    if ( IsOwnerDrawn() )
    {
        // we don't need to do anything for owner drawn items, they will redraw
        // themselves using the new text the next time they're displayed
        return;
    }
#endif // owner drawn

    // update the text of the native menu item
    WinStruct<MENUITEMINFO> info;

    // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't
    // work as it resets the menu bitmap, so we need to first get the old item
    // state and then modify it
    const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95;
    info.fMask = MIIM_STATE |
                 MIIM_ID |
                 MIIM_SUBMENU |
                 MIIM_CHECKMARKS |
                 MIIM_DATA;
    if ( isLaterThanWin95 )
        info.fMask |= MIIM_BITMAP | MIIM_FTYPE;
    else
        info.fMask |= MIIM_TYPE;
    if ( !::GetMenuItemInfo(hMenu, id, FALSE, &info) )
    {
        wxLogLastError(wxT("GetMenuItemInfo"));
        return;
    }

    if ( isLaterThanWin95 )
        info.fMask |= MIIM_STRING;
    //else: MIIM_TYPE already specified
    info.dwTypeData = wxMSW_CONV_LPTSTR(m_text);
    info.cch = m_text.length();
    if ( !::SetMenuItemInfo(hMenu, id, FALSE, &info) )
    {
        wxLogLastError(wxT("SetMenuItemInfo"));
    }
}