Esempio n. 1
0
static LRESULT
html_notify_text(html_t* html, UINT code, const WCHAR* text)
{
    /* Note we shamelessly misuse this also for URL notifications, as the
     * MC_NMHTMLURL and MC_NMHTMLTEXT are binary compatible.
     * They are separate mainly for historical reasons.
     */

    MC_NMHTMLTEXTW notify;
    LRESULT res;
    BOOL need_free = FALSE;

    HTML_TRACE("html_notify_text: code=%d str='%S'", code, text ? text : L"[null]");

    notify.hdr.hwndFrom = html->win;
    notify.hdr.idFrom = GetDlgCtrlID(html->win);
    notify.hdr.code = code;
    if(text == NULL) {
        notify.pszText = L"";
    } else if(html->unicode_notifications) {
        notify.pszText = text;
    } else {
        notify.pszText = (WCHAR*) mc_str(text, MC_STRW, MC_STRA);
        need_free = TRUE;
    }

    res = MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, &notify);

    if(need_free)
        free((WCHAR*)notify.pszText);

    return res;
}
Esempio n. 2
0
static void
html_notify_format(html_t* html)
{
    LRESULT lres;
    lres = MC_SEND(html->notify_win, WM_NOTIFYFORMAT, html->win, NF_QUERY);
    html->unicode_notifications = (lres == NFR_UNICODE ? 1 : 0);
    HTML_TRACE("html_notify_format: Will use %s notifications.",
               html->unicode_notifications ? "Unicode" : "ANSI");
}
Esempio n. 3
0
File: grid.c Progetto: UIKit0/mctrl
static void
grid_notify_format(grid_t* grid)
{
    LRESULT lres;
    lres = MC_SEND(grid->notify_win, WM_NOTIFYFORMAT, grid->win, NF_QUERY);
    grid->unicode_notifications = (lres == NFR_UNICODE ? 1 : 0);
    GRID_TRACE("grid_notify_format: Will use %s notifications.",
               grid->unicode_notifications ? "Unicode" : "ANSI");
}
Esempio n. 4
0
static LRESULT
button_update_ui_state(HWND win, button_t* button, WPARAM wp, LPARAM lp)
{
    LRESULT ret;
    DWORD flags;

    ret = CallWindowProc(orig_button_proc, win, WM_UPDATEUISTATE, wp, lp);
    flags = MC_SEND(win, WM_QUERYUISTATE, 0, 0);
    button->hide_focus = (flags & UISF_HIDEFOCUS) ? 1 : 0;
    button->hide_accel = (flags & UISF_HIDEACCEL) ? 1 : 0;
    if(!button->no_redraw)
        InvalidateRect(win, NULL, FALSE);
    return ret;
}
Esempio n. 5
0
static HBRUSH
button_send_ctlcolorbtn(HWND win, HDC dc)
{
    HBRUSH brush;
    HWND parent = GetAncestor(win, GA_PARENT);

    if(parent == NULL)
        parent = win;
    brush = (HBRUSH) MC_SEND(parent, WM_CTLCOLORBTN, dc, win);
    if(MC_ERR(brush == NULL)) {
        /* The parent window procedure does not handle WM_CTLCOLORBTN
         * correctly. Maybe it forgot to call DefWindowProc?
         *
         * Wine-1.1.27/dlls/user32/button.c does this workaround, so
         * probably they have good reason to do so. Perhaps they noticed
         * Microsoft standard controls do that too so lets try to be
         * consistent. */
        MC_TRACE("button_send_ctlcolorbtn: Parent window does not handle "
                 "WM_CTLCOLORBTN correctly.");
        brush = (HBRUSH) DefWindowProc(parent, WM_CTLCOLORBTN, (WPARAM)dc, (LPARAM)win);
    }
    return brush;
}
Esempio n. 6
0
static void
button_paint_icon(HWND win, button_t* button, HDC dc)
{
    HICON icon;
    RECT rect;
    RECT content;
    int state;
    SIZE size;
    UINT flags;
    HFONT font, old_font;
    int old_bk_mode;
    COLORREF old_text_color;
    HRGN old_clip;

    /* When theming is not used, we keep all the work on COMCTL32 button
     * implementation. */
    MC_ASSERT(button->theme != NULL);

    GetClientRect(win, &rect);

    icon = (HICON) MC_SEND(win, BM_GETIMAGE, IMAGE_ICON, 0);
    font = (HFONT) MC_SEND(win, WM_GETFONT, 0, 0);
    if(font == NULL)
        font = GetStockObject(SYSTEM_FONT);

    old_font = SelectObject(dc, font);
    old_bk_mode = GetBkMode(dc);
    old_text_color = GetTextColor(dc);
    old_clip = get_clip(dc);

    /* Draw background */
    if(button->style & WS_DISABLED) {
        state = PBS_DISABLED;
    } else {
        LRESULT s = MC_SEND(win, BM_GETSTATE, 0, 0);
        if(s & BST_PUSHED)
            state = PBS_PRESSED;
        else if(s & BST_HOT)
            state = PBS_HOT;
        else if(button->style & BS_DEFPUSHBUTTON)
            state = PBS_DEFAULTED;
        else
            state = PBS_NORMAL;
    }
    if(mcIsThemeBackgroundPartiallyTransparent(button->theme, BP_PUSHBUTTON, state))
        mcDrawThemeParentBackground(win, dc, &rect);
    mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state, &rect, &rect);

    /* Get content rectangle of the button and clip DC to it */
    mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state, &rect, &content);
    IntersectClipRect(dc, content.left, content.top, content.right, content.bottom);

    /* Draw focus rectangle */
    if(MC_SEND(win, BM_GETSTATE, 0, 0) & BST_FOCUS) {
        if(!button->hide_focus)
            DrawFocusRect(dc, &content);
    }

    /* Draw the contents (i.e. the icon) */
    if(icon != NULL) {
        mc_icon_size(icon, &size);
        flags = DST_ICON;
        if(button->style & WS_DISABLED)
            flags |= DSS_DISABLED;
        DrawState(dc, NULL, NULL, (LPARAM) icon, 0, (rect.right + rect.left - size.cx) / 2,
                  (rect.bottom + rect.top - size.cy) / 2, size.cx, size.cy, flags);
    }

    /* Revert DC into original state */
    SelectObject(dc, old_font);
    SetBkMode(dc, old_bk_mode);
    SetTextColor(dc, old_text_color);
    SelectObject(dc, old_clip);
}
Esempio n. 7
0
static LRESULT CALLBACK
button_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp)
{
    button_t* button = (button_t*) GetWindowLongPtr(win, extra_offset);

    /* Window procedure for our subclassed BUTTON does some logic if
     * either [1] the control is split button and system does not support it
     *            (i.e. Windows is older then Vista).
     *     or [2] the control is BS_ICON and theming is in use, as std.
     *            control draws in the old unthemed style this kind of button.
     * In all other cases all messages are just forwarded to the standard
     * Microsoft button procedure.
     */

    switch(msg) {
        case WM_PAINT:
        case WM_PRINTCLIENT:
        {
            BOOL fake_split;
            BOOL fake_icon;
            PAINTSTRUCT ps;
            HDC dc;

            fake_split = button_is_fake_split(button);
            fake_icon = button_is_fake_icon(button);
            if(!fake_split  &&  !fake_icon) {
                /* Keep it on original proc */
                break;
            }

            if(msg == WM_PAINT)
                dc = BeginPaint(win, &ps);
            else
                dc = (HDC) wp;

            if(!button->no_redraw) {
                if(fake_split)
                    button_paint_split(win, button, dc);
                else
                    button_paint_icon(win, button, dc);
            }

            if(msg == WM_PAINT)
                EndPaint(win, &ps);
            return 0;
        }

        case WM_LBUTTONDOWN:
            if(button_is_fake_split(button)) {
                POINT pt = { GET_X_LPARAM(lp), GET_Y_LPARAM(lp) };
                RECT rect;

                SetFocus(win);
                GetClientRect(win, &rect);
                rect.left = rect.right - DROPDOWN_W;

                if(mc_rect_contains_pt(&rect, &pt)) {
                    /* Handle the click in the drop-down part */
                    MC_NMBCDROPDOWN notify;

                    button->is_dropdown_pushed = 1;
                    InvalidateRect(win, &rect, TRUE);

                    notify.hdr.hwndFrom = win;
                    notify.hdr.idFrom = GetWindowLong(win, GWL_ID);
                    notify.hdr.code = MC_BCN_DROPDOWN;
                    mc_rect_copy(&notify.rcButton, &rect);
                    MC_SEND(GetAncestor(win, GA_PARENT), WM_NOTIFY, notify.hdr.idFrom, &notify);
                    /* We unpush immediately after the parent handles the
                     * notification. Usually it takes some time - parent
                     * typically shows some popup-menu or other stuff
                     * which includes a modal eventloop and/or mouse capture.
                     */
                    button->is_dropdown_pushed = 0;
                    InvalidateRect(win, NULL, TRUE);
                    return 0;
                }
            }
            break;

        case WM_LBUTTONDBLCLK:
            if(button_is_fake_split(button)) {
                RECT rect;

                GetClientRect(win, &rect);
                rect.left = rect.right - DROPDOWN_W;
                if(mc_rect_contains_pos(&rect, lp)) {
                    /* We ignore duble-click in the drop-down part. */
                    return 0;
                }
            }
            break;

        case WM_GETDLGCODE:
            /* Handling this message allows the dialogs to set the button
             * as default, as it is done for normal push buttons. Unfortunately
             * it causes other problems. See the comment in WM_STYLECHANGING.
             */
            if(button_is_fake_split(button)) {
                if((button->style & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) {
                    BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_DEFPUSHBUTTON");
                    return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
                }
                if((button->style & BS_TYPEMASK) == MC_BS_SPLITBUTTON) {
                    BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_UNDEFPUSHBUTTON");
                    return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
                }
            }
            break;

        case BM_SETSTATE:
            if(button_is_fake_split(button)) {
                CallWindowProc(orig_button_proc, win, msg, wp, lp);
                /* USER32.DLL does some painting in BM_SETSTATE. Repaint
                 * the split button. */
                InvalidateRect(win, NULL, TRUE);
                return 0;
            }
            break;

        case BM_GETSTATE:
            if(button_is_fake_split(button)) {
                DWORD s = CallWindowProc(orig_button_proc, win, msg, wp, lp);
                if(button->is_dropdown_pushed)
                    s |= MC_BST_DROPDOWNPUSHED;
                return s;
            }
            break;

        case BM_SETSTYLE:
            if(button_is_fake_split(button)) {
                BUTTON_TRACE("button_proc(BM_SETSTYLE): split style fixup");
                wp &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON);
                wp |= MC_BS_SPLITBUTTON;
                CallWindowProc(orig_button_proc, win, msg, wp, lp);
                button->style = GetWindowLong(win, GWL_STYLE);
                return 0;
            }
            break;

        case WM_SETREDRAW:
            button->no_redraw = !wp;
            break;

        case WM_STYLECHANGING:
            if(button_is_fake_split(button)) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lp;
                if((ss->styleOld & BS_TYPEMASK) == MC_BS_SPLITBUTTON  ||
                   (ss->styleOld & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) {
                    /* On older system which do not support split buttons
                     * (i.e. 2000, XP), the dialog procedure does not handle
                     * moving the default state correctly: It accidentaly
                     * removes our split button button type. Hence we perform
                     * this fixup.
                     *
                     * Unfortunately this means that app. cannot freely change
                     * BS_SPLITBUTTON to BS_BUTTON with SetWindowLong(GWL_STYLE)
                     * as this will prevent that too... */
                    BUTTON_TRACE("button_proc(WM_STYLECHANGING): split style fixup");
                    ss->styleNew &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON);
                    ss->styleNew |= MC_BS_SPLITBUTTON;
                }
            }
            break;

        case WM_STYLECHANGED:
            if(wp == GWL_STYLE) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lp;
                button->style = ss->styleNew;
            }
            break;

        case WM_THEMECHANGED:
            if(button->theme)
                mcCloseThemeData(button->theme);
            button->theme = mcOpenThemeData(win, button_tc);
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_SYSCOLORCHANGE:
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_UPDATEUISTATE:
            button_update_ui_state(button, LOWORD(wp), HIWORD(wp));
            InvalidateRect(win, NULL, FALSE);
            break;

        case WM_NCCREATE:
            if(MC_ERR(!CallWindowProc(orig_button_proc, win, WM_NCCREATE, wp, lp))) {
                MC_TRACE_ERR("button_proc(WM_NCCREATE): orig_button_proc() failed");
                return FALSE;
            }
            button = (button_t*) malloc(sizeof(button_t));
            if(MC_ERR(button == NULL)) {
                MC_TRACE("button_proc(WM_CREATE): malloc() failed.");
                return FALSE;
            }
            memset(button, 0, sizeof(button_t));
            button->style = ((CREATESTRUCT*)lp)->style;
            SetWindowLongPtr(win, extra_offset, (LONG_PTR) button);
            return TRUE;

        case WM_CREATE:
            if(MC_ERR(CallWindowProc(orig_button_proc, win, WM_CREATE, wp, lp) != 0)) {
                MC_TRACE_ERR("button_proc(WM_CREATE): orig_button_proc() failed");
                return -1;
            }
            button->theme = mcOpenThemeData(win, button_tc);

            {
                WORD ui_state = MC_SEND(win, WM_QUERYUISTATE, 0, 0);
                button->hide_focus = (ui_state & UISF_HIDEFOCUS) ? 1 : 0;
                button->hide_accel = (ui_state & UISF_HIDEACCEL) ? 1 : 0;
            }
            return 0;

        case WM_DESTROY:
            if(button->theme) {
                mcCloseThemeData(button->theme);
                button->theme = NULL;
            }
            break;

        case WM_NCDESTROY:
            if(button)
                free(button);
            break;
    }

    return CallWindowProc(orig_button_proc, win, msg, wp, lp);
}
Esempio n. 8
0
static void
button_paint_split(HWND win, button_t* button, HDC dc)
{
    RECT rect;
    RECT rect_left, rect_right;
    int state_left, state_right;
    int text_offset = 0;
    HFONT font, old_font;
    int old_bk_mode;
    COLORREF old_text_color;
    HRGN old_clip;
    HICON glyph;
    int width_right = DROPDOWN_W;

    glyph = ImageList_GetIcon(mc_bmp_glyphs, MC_BMP_GLYPH_MORE_OPTIONS, ILD_TRANSPARENT);
    GetClientRect(win, &rect);

    font = (HFONT) MC_SEND(win, WM_GETFONT, 0, 0);
    if(font == NULL)
        font = GetStockObject(SYSTEM_FONT);

    old_font = SelectObject(dc, font);
    old_bk_mode = GetBkMode(dc);
    old_text_color = GetTextColor(dc);
    old_clip = get_clip(dc);

    /* Draw what's common for left and right parts background. */
    if(!button->theme  &&  (button->style & BS_DEFPUSHBUTTON)) {
        SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
        Rectangle(dc, rect.left, rect.top, rect.right, rect.bottom);
        mc_rect_inflate(&rect, -1, -1);
        width_right--;
    }

    /* Setup subrectangles (mainpart 1 and push-down part 2) */
    mc_rect_copy(&rect_left, &rect);
    rect_left.right -= width_right;
    mc_rect_copy(&rect_right, &rect);
    rect_right.left = rect_left.right;

    /* Draw background. */
    if(button->theme) {
        UINT transparent;
        RECT tmp;

        /* Determine styles for left and right parts */
        if(button->style & WS_DISABLED) {
            state_left = state_right = PBS_DISABLED;
        } else {
            LRESULT state;

            state = MC_SEND(win, BM_GETSTATE, 0, 0);
            if(state & MC_BST_DROPDOWNPUSHED) {
                state_left = PBS_NORMAL;
                state_right = PBS_PRESSED;
            } else {
                if(state & BST_PUSHED)
                    state_left = state_right = PBS_PRESSED;
                else if(state & BST_HOT)
                    state_left = state_right = PBS_HOT;
                else if(button->style & BS_DEFPUSHBUTTON)
                    state_left = state_right = PBS_DEFAULTED;
                else
                    state_left = state_right = PBS_NORMAL;
            }
        }

        /* Handle (semi-)transparent themes. */
        transparent = 0;
        if(mcIsThemeBackgroundPartiallyTransparent(button->theme,
                    BP_PUSHBUTTON, state_left))
            transparent |= 0x1;
        if(mcIsThemeBackgroundPartiallyTransparent(button->theme,
                    BP_PUSHBUTTON, state_right))
            transparent |= 0x2;
        switch(transparent) {
            case 0x1:
                mcDrawThemeParentBackground(win, dc, &rect_left);
                break;
            case 0x2:
                mcDrawThemeParentBackground(win, dc, &rect_right);
                break;
            case 0x3:
                mcDrawThemeParentBackground(win, dc, &rect);
                break;
        }

        /* Draw backgrond. */
        mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state_left, &rect, &rect_left);
        mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state_right, &rect, &rect_right);

        /* Deflate both rects to content rects only */
        mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state_left, &rect_left, &tmp);
        rect_left.left = tmp.left;
        rect_left.top = tmp.top;
        rect_left.bottom = tmp.bottom;
        mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state_right, &rect_right, &tmp);
        rect_right.top = tmp.top;
        rect_right.right = tmp.right;
        rect_right.bottom = tmp.bottom;

        /* Draw delimiter of left and right parts. */
        rect_right.top += 1;
        rect_right.bottom -= 1;
        mcDrawThemeEdge(button->theme, dc, BP_PUSHBUTTON, state_right, &rect_right, BDR_SUNKEN, BF_LEFT, NULL);
        rect_right.left = tmp.left;
    } else {
        /* Determine styles for left and right parts */
        if(button->style & WS_DISABLED) {
            state_left = state_right = DFCS_INACTIVE;
        } else {
            LRESULT s = MC_SEND(win, BM_GETSTATE, 0, 0);
            if(s & MC_BST_DROPDOWNPUSHED) {
                state_left = 0;
                state_right = DFCS_PUSHED;
            } else {
                if(s & BST_PUSHED) {
                    state_left = state_right = DFCS_PUSHED;
                } else {
                    state_left = state_right = 0;
                }
            }
        }

        button_send_ctlcolorbtn(win, dc);

        /* Draw control edges */
        IntersectClipRect(dc, rect_left.left, rect_left.top, rect_left.right, rect_left.bottom);
        DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH | state_left);
        SelectClipRgn(dc, NULL);
        IntersectClipRect(dc, rect_right.left, rect_right.top, rect_right.right, rect_right.bottom);
        DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH | state_right);

        /* Parts which are pushed, should have the contents moved a bit */
        if(state_left == DFCS_PUSHED)
            mc_rect_offset(&rect_left, 1, 1);
        if(state_right == DFCS_PUSHED)
            mc_rect_offset(&rect_right, 1, 1);

        /* Draw delimiter */
        if(state_left == state_right) {
            DrawEdge(dc, &rect_right, BDR_SUNKENOUTER | BDR_RAISEDINNER, BF_LEFT | BF_SOFT);
        } else {
            rect_right.left--;
            DrawEdge(dc, &rect_right, BDR_SUNKENOUTER, BF_LEFT | BF_SOFT);
            rect_right.left++;
        }

        /* Adjust for the outer control edges */
        mc_rect_inflate(&rect_left, 0, -2);
        rect_left.left += 2;
        mc_rect_inflate(&rect_right, -2, -2);
    }

    /* Draw focus rectangle. */
    if((MC_SEND(win, BM_GETSTATE, 0, 0) & BST_FOCUS) && !button->hide_focus) {
        SelectClipRgn(dc, NULL);
        if(button->theme) {
            mc_rect_set(&rect, rect_left.left, rect_left.top,
                        rect_right.right - DROPDOWN_W, rect_right.bottom);
            DrawFocusRect(dc, &rect);
        } else {
            mc_rect_inflate(&rect_left, -1, -2);
            DrawFocusRect(dc, &rect_left);
            mc_rect_inflate(&rect_left, -1, -1);
        }
    }

    /* Draw glyph into the right part */
    SelectClipRgn(dc, NULL);
    IntersectClipRect(dc, rect_right.left, rect_right.top,
                          rect_right.right, rect_right.bottom);
    DrawIconEx(dc, (rect_right.right + rect_right.left - MC_BMP_GLYPH_W) / 2,
                   (rect_right.bottom + rect_right.top - MC_BMP_GLYPH_H) / 2,
                   glyph, MC_BMP_GLYPH_W, MC_BMP_GLYPH_H, 0, NULL, DI_NORMAL);

    /* Draw left part contents */
    SelectClipRgn(dc, NULL);
    IntersectClipRect(dc, rect_left.left, rect_left.top,
                          rect_left.right, rect_left.bottom);
    if(button->style & BS_ICON) {
        /* Paint (BS_SPLITBUTTON | BS_ICON). Note that this is used even on
         * Vista, as according to some my testing this style combination
         * is not supported there... */
        HICON icon;

        icon = (HICON) MC_SEND(win, BM_GETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) 0);
        if(icon != NULL) {
            SIZE size;
            UINT flags;

            mc_icon_size(icon, &size);

            flags = DST_ICON;
            if(button->style & WS_DISABLED)
                flags |= DSS_DISABLED;

            DrawState(dc, NULL, NULL, (LPARAM) icon, 0,
                      (rect_left.right + rect_left.left - size.cx) / 2,
                      (rect_left.bottom + rect_left.top - size.cy) / 2,
                      size.cx, size.cy, flags);
        }
    } else {
        /* Paint text label */
        TCHAR buffer[256];
        int n;
        UINT flags = 0;

        /* Setup flags for TextOut/mcDrawThemeText */
        switch(button->style & (BS_LEFT | BS_CENTER | BS_RIGHT)) {
            case BS_LEFT:
                flags |= DT_LEFT;
                break;
            case BS_RIGHT:
                flags |= DT_RIGHT;
                break;
            default:
                if(GetWindowLong(win, GWL_EXSTYLE) & WS_EX_RIGHT)
                    flags |= DT_RIGHT;
                else
                    flags |= DT_CENTER;
                break;
        }
        switch(button->style & (BS_TOP | BS_VCENTER | BS_BOTTOM)) {
            case BS_TOP:
                flags |= DT_TOP;
                break;
            case BS_BOTTOM:
                flags |= DT_BOTTOM;
                break;
            default:
                flags |= DT_VCENTER;
                break;
        }
        if(button->style & BS_MULTILINE)
            flags |= DT_WORDBREAK;
        else
            flags |= DT_SINGLELINE;

        if(button->hide_accel)
            flags |= DT_HIDEPREFIX;

        n = MC_SEND(win, WM_GETTEXT, MC_ARRAY_SIZE(buffer), buffer);

        if(button->theme) {
            mcDrawThemeText(button->theme, dc, BP_PUSHBUTTON,
                        state_left, buffer, n, flags, 0, &rect_left);
        } else {
            SetBkMode(dc, TRANSPARENT);
            SetTextColor(dc, GetSysColor(COLOR_BTNTEXT));
            mc_rect_offset(&rect_left, text_offset, text_offset);
            DrawText(dc, buffer, n, &rect_left, flags);
        }
    }

    SelectObject(dc, old_font);
    SetBkMode(dc, old_bk_mode);
    SetTextColor(dc, old_text_color);
    SelectObject(dc, old_clip);
}
Esempio n. 9
0
BOOL MCTRL_API
mcMenubar_HandleRebarChevronPushed(HWND hwndMenubar,
                                   NMREBARCHEVRON* lpRebarChevron)
{
    REBARBANDINFO band_info;
    menubar_t* mb;
    RECT rect;
    HMENU menu;
    MENUITEMINFO mii;
    TCHAR buffer[MENUBAR_ITEM_LABEL_MAXSIZE];
    int i, n;
    TPMPARAMS params;

    /* Verify lpRebarChevron is from notification we assume. */
    if(MC_ERR(lpRebarChevron->hdr.code != RBN_CHEVRONPUSHED)) {
        MC_TRACE("mcMenubar_HandleRebarChevronPushed: Not RBN_CHEVRONPUSHED");
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    /* Verify/get the menubar handle */
    band_info.cbSize = REBARBANDINFO_V3_SIZE;
    band_info.fMask = RBBIM_CHILD;
    MC_SEND(lpRebarChevron->hdr.hwndFrom, RB_GETBANDINFO, lpRebarChevron->uBand, &band_info);
    if(hwndMenubar != NULL) {
        if(MC_ERR(hwndMenubar != band_info.hwndChild)) {
            MC_TRACE("mcMenubar_HandleRebarChevronPushed: "
                     "Notification not about band with the specified menubar.");
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }
    } else {
        hwndMenubar = band_info.hwndChild;
        if(MC_ERR(hwndMenubar == NULL)) {
            MC_TRACE("mcMenubar_HandleRebarChevronPushed: "
                     "The band does not host any child window");
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }
    }

    /* Create popup menu for not completely visible menu items */
    mb = (menubar_t*) GetWindowLongPtr(hwndMenubar, extra_offset);
    GetClientRect(hwndMenubar, &rect);
    menu = CreatePopupMenu();
    if(MC_ERR(menu == NULL)) {
        MC_TRACE_ERR("mcMenubar_HandleRebarChevronPushed: CreatePopupMenu() failed.");
        return FALSE;
    }
    mii.cbSize = sizeof(MENUITEMINFO);
    mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
    mii.dwTypeData = buffer;
    mii.cch = MC_SIZEOF_ARRAY(buffer);
    n = MENUBAR_SENDMSG(hwndMenubar, TB_BUTTONCOUNT, 0, 0);
    for(i = n-1; i >= 0; i--) {
        RECT item_rect;

        MENUBAR_SENDMSG(hwndMenubar, TB_GETITEMRECT, i, &item_rect);
        if(item_rect.right < rect.right)
            break;

        mii.cch = MC_SIZEOF_ARRAY(buffer);
        GetMenuItemInfo(mb->menu, i, TRUE, &mii);
        InsertMenuItem(menu, 0, TRUE, &mii);
    }
    params.cbSize = sizeof(TPMPARAMS);
    mc_rect_copy(&params.rcExclude, &lpRebarChevron->rc);

    /* Run the menu */
    MapWindowPoints(hwndMenubar, NULL, (POINT*) &params.rcExclude, 2);
    TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
                     params.rcExclude.left, params.rcExclude.bottom, mb->win, &params);

    /* Destroy the popup menu. Note submenus have to survive as they are shared
     * with the menubar itself. */
    n = GetMenuItemCount(menu);
    for(i = 0; i < n; i++)
        RemoveMenu(menu, 0, MF_BYPOSITION);
    DestroyMenu(menu);

    return TRUE;
}
Esempio n. 10
0
static LRESULT CALLBACK
menubar_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp)
{
    menubar_t* mb = (menubar_t*) GetWindowLongPtr(win, extra_offset);

    switch(msg) {
        case MC_MBM_REFRESH:
            lp = (LPARAM)mb->menu;
            /* no break */
        case MC_MBM_SETMENU:
            return (menubar_set_menu(mb, (HMENU)lp, (msg == MC_MBM_REFRESH)) == 0 ? TRUE : FALSE);

        case TB_SETPARENT:
        case CCM_SETNOTIFYWINDOW:
        {
            HWND old = mb->notify_win;
            mb->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT));
            return (LRESULT) old;
        }

        case WM_COMMAND:
            MENUBAR_TRACE("menubar_proc(WM_COMMAND): code=%d; wid=%d; control=%p",
                          (int)HIWORD(wp), (int)LOWORD(wp), (HWND)lp);
            if(lp == 0  &&  HIWORD(wp) == 0)  /* msg came from the menu */
                return MC_SEND(mb->notify_win, msg, wp, lp);
            break;

        case WM_NOTIFY:
        {
            NMHDR* hdr = (NMHDR*) lp;
            if(hdr->hwndFrom == win)
                return menubar_notify(mb, hdr);
            break;
        }

        case WM_ENTERMENULOOP:
        case WM_EXITMENULOOP:
        case WM_CONTEXTMENU:
        case WM_INITMENU:
        case WM_INITMENUPOPUP:
        case WM_UNINITMENUPOPUP:
        case WM_MENUSELECT:
        case WM_MENUCHAR:
        case WM_MENURBUTTONUP:
        case WM_MENUCOMMAND:
        case WM_MENUDRAG:
        case WM_MENUGETOBJECT:
        case WM_MEASUREITEM:
        case WM_DRAWITEM:
            return MC_SEND(mb->notify_win, msg, wp, lp);

        case WM_KEYDOWN:
        case WM_SYSKEYDOWN:
            if(menubar_key_down(mb, wp, lp))
                return 0;
            break;

        case WM_GETDLGCODE:
            return MENUBAR_SENDMSG(win, msg, wp, lp) | DLGC_WANTALLKEYS | DLGC_WANTARROWS;

        case WM_NCCREATE:
            if(MC_ERR(MENUBAR_SENDMSG(win, msg, wp, lp) == FALSE)) {
                MC_TRACE_ERR("menubar_proc: MENUBAR_SENDMSG(WM_NCCREATE) failed");
                return FALSE;
            }
            mb = menubar_nccreate(win, (CREATESTRUCT*) lp);
            if(MC_ERR(mb == NULL))
                return FALSE;
            SetWindowLongPtr(win, extra_offset, (LONG_PTR)mb);
            return TRUE;

        case WM_SETFOCUS:
            MENUBAR_TRACE("menubar_proc(WM_SETFOCUS): old focus %p", (HWND) wp);
            if(win != (HWND) wp)
                mb->old_focus = (HWND) wp;
            active_menubar = mb;
            break;

        case WM_KILLFOCUS:
            MENUBAR_TRACE("menubar_proc: WM_KILLFOCUS");
            mb->old_focus = NULL;
            MENUBAR_SENDMSG(mb->win, TB_SETHOTITEM, -1, 0);
            menubar_update_ui_state(mb, FALSE);
            active_menubar = NULL;
            break;

        case WM_CREATE:
            return menubar_create(mb, (CREATESTRUCT*) lp);

        case WM_DESTROY:
            menubar_destroy(mb);
            break;

        case WM_NCDESTROY:
            if(mb) {
                menubar_ncdestroy(mb);
                mb = NULL;
            }
            break;

        /* Disable those standard toolbar messages, which modify contents of
         * the toolbar, as it is our internal responsibility to set it
         * according to the menu. */
        case TB_ADDBITMAP:
        case TB_ADDSTRING:
            MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg);
            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
            return -1;
        case TB_ADDBUTTONS:
        case TB_BUTTONSTRUCTSIZE:
        case TB_CHANGEBITMAP:
        case TB_DELETEBUTTON:
        case TB_ENABLEBUTTON:
        case TB_HIDEBUTTON:
        case TB_INDETERMINATE:
        case TB_INSERTBUTTON:
        case TB_LOADIMAGES:
        case TB_MARKBUTTON:
        case TB_MOVEBUTTON:
        case TB_PRESSBUTTON:
        case TB_REPLACEBITMAP:
        case TB_SAVERESTORE:
        case TB_SETANCHORHIGHLIGHT:
        case TB_SETBITMAPSIZE:
        case TB_SETBOUNDINGSIZE:
        case TB_SETCMDID:
        case TB_SETDISABLEDIMAGELIST:
        case TB_SETHOTIMAGELIST:
        case TB_SETIMAGELIST:
        case TB_SETINSERTMARK:
        case TB_SETPRESSEDIMAGELIST:
        case TB_SETSTATE:
            MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg);
            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
            return 0;  /* FALSE == NULL == 0 */

        case TB_CUSTOMIZE:
            /* Actually we suppress TB_CUSTOMIZE as the message above (i.e.
             * not passing it into the original proc), but we also misuse
             * is for our internal purpose of showing the popup menu. */
            menubar_perform_dropdown(mb);
            return 0;
    }

    return MENUBAR_SENDMSG(win, msg, wp, lp);
}
Esempio n. 11
0
static LRESULT
menubar_notify(menubar_t* mb, NMHDR* hdr)
{
    switch(hdr->code) {
        case TBN_DROPDOWN:
        {
            NMTOOLBAR* info = (NMTOOLBAR*) hdr;
            MENUBAR_TRACE("menubar_notify(%p, TBN_DROPDOWN, %d)", mb, info->iItem);
            menubar_dropdown(mb, info->iItem, FALSE);
            break;
        }

        case TBN_HOTITEMCHANGE:
        {
            NMTBHOTITEM* info = (NMTBHOTITEM*) hdr;
            MENUBAR_TRACE("menubar_notify(%p, TBN_HOTITEMCHANGE, %d -> %d)", mb,
                          (info->dwFlags & HICF_ENTERING) ? -1 : info->idOld,
                          (info->dwFlags & HICF_LEAVING) ? -1 : info->idNew);
            mb->hot_item = (info->dwFlags & HICF_LEAVING) ? -1 : info->idNew;
            break;
        }

        case NM_CUSTOMDRAW:
        {
            NMTBCUSTOMDRAW* info = (NMTBCUSTOMDRAW*) hdr;
            switch(info->nmcd.dwDrawStage) {
                case CDDS_PREPAINT:
                    if(mc_win_version >= MC_WIN_VISTA  &&  mcIsAppThemed())
                        return CDRF_DODEFAULT;
                    else if(mc_win_version < MC_WIN_XP)
                        return CDRF_DODEFAULT;
                    else
                        return CDRF_NOTIFYITEMDRAW;

                case CDDS_ITEMPREPAINT:
                {
                    int text_color_id;
                    int bk_color_id;
                    TCHAR buffer[MENUBAR_ITEM_LABEL_MAXSIZE];
                    TBBUTTONINFO btn;
                    UINT flags = MENUBAR_DTFLAGS;
                    HDC dc = info->nmcd.hdc;
                    HFONT old_font;

                    if(info->nmcd.uItemState & (CDIS_HOT | CDIS_SELECTED)) {
                        text_color_id = COLOR_HIGHLIGHTTEXT;
                        bk_color_id = COLOR_HIGHLIGHT;
                    } else {
                        text_color_id = COLOR_MENUTEXT;
                        bk_color_id = -1;
                    }

                    btn.cbSize = sizeof(TBBUTTONINFO);
                    btn.dwMask = TBIF_TEXT;
                    btn.pszText = buffer;
                    btn.cchText = MC_SIZEOF_ARRAY(buffer);
                    MENUBAR_SENDMSG(mb->win, TB_GETBUTTONINFO, info->nmcd.dwItemSpec, &btn);

                    if(MENUBAR_SENDMSG(mb->win, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL)
                        flags |= DT_HIDEPREFIX;

                    if(bk_color_id >= 0)
                        FillRect(dc, &info->nmcd.rc, (HBRUSH) (INT_PTR) (bk_color_id+1));

                    SetTextColor(dc, GetSysColor(text_color_id));
                    old_font = SelectObject(dc, (HFONT) MENUBAR_SENDMSG(mb->win, WM_GETFONT, 0, 0));
                    SetBkMode(dc, TRANSPARENT);
                    DrawText(dc, buffer, -1, &info->nmcd.rc, flags);
                    SelectObject(dc, old_font);
                    return CDRF_SKIPDEFAULT;
                }

                default:
                    return CDRF_DODEFAULT;
            }
        }
    }

    return MC_SEND(mb->notify_win, WM_NOTIFY, hdr->idFrom, hdr);
}
Esempio n. 12
0
static HRESULT STDMETHODCALLTYPE
dispatch_Invoke(IDispatch* self, DISPID disp_id, REFIID riid, LCID lcid,
                WORD flags, DISPPARAMS* params, VARIANT* var_res,
                EXCEPINFO* except, UINT* arg_err)
{
    html_t* html = MC_HTML_FROM_DISPTACH(self);

    switch(disp_id) {
        case DISPID_BEFORENAVIGATE2:
        {
            BSTR url = V_BSTR(V_VARIANTREF(&params->rgvarg[5]));
            VARIANT_BOOL* cancel = V_BOOLREF(&params->rgvarg[0]);

            HTML_TRACE("dispatch_Invoke: DISPID_BEFORENAVIGATE2(%S)", url);

            if(url != NULL  &&  wcsncmp(url, L"app:", 4) == 0) {
                html_notify_text(html, MC_HN_APPLINK, url);
                *cancel = VARIANT_TRUE;
            }
            break;
        }

#if 0
        /* Unfortunately, IE does not send DISPID_DOCUMENTCOMPLETE
         * when refreshing the page (e.g. from context menu). So we workaround
         * via DISPID_PROGRESSCHANGE below. */
        case DISPID_DOCUMENTCOMPLETE:
        {
            BSTR url = V_BSTR(V_VARIANTREF(&params->rgvarg[0]));
            html_notify_text(html, MC_HN_DOCUMENTCOMPLETE, url);
            break;
        }
#endif

        case DISPID_PROGRESSCHANGE:
        {
            LONG progress_max = V_I4(&params->rgvarg[0]);
            LONG progress = V_I4(&params->rgvarg[1]);
            MC_NMHTMLPROGRESS notify;
            HTML_TRACE("dispatch_Invoke: DISPID_PROGRESSCHANGE(%ld, %ld)",
                       progress, progress_max);

            /* Send also notification about the progress */
            notify.hdr.hwndFrom = html->win;
            notify.hdr.idFrom = GetDlgCtrlID(html->win);
            notify.hdr.code = MC_HN_PROGRESS;
            notify.lProgress = progress;
            notify.lProgressMax = progress_max;
            MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, &notify);

            /* This replaces DISPID_DOCUMENTCOMPLETE above */
            if(progress < 0  ||  progress_max < 0) {
                IWebBrowser2* browser_iface;
                HRESULT hr;

                hr = html->browser_obj->lpVtbl->QueryInterface(html->browser_obj,
                        &IID_IWebBrowser2, (void**)&browser_iface);
                if(MC_ERR(hr != S_OK  ||  browser_iface == NULL)) {
                    MC_TRACE("dispatch_Invoke(DISPID_PROGRESSCHANGE): "
                             "QueryInterface(IID_IWebBrowser2) failed [0x%lx]", hr);
                } else {
                    BSTR url = NULL;
                    hr = browser_iface->lpVtbl->get_LocationURL(browser_iface, &url);
                    if(hr == S_OK && url != NULL) {
                        html_notify_text(html, MC_HN_DOCUMENTCOMPLETE, url);
                        html_SysFreeString(url);
                    }
                    browser_iface->lpVtbl->Release(browser_iface);
                }
            }
            break;
        }

        case DISPID_STATUSTEXTCHANGE:
            HTML_TRACE("dispatch_Invoke: DISPID_STATUSTEXTCHANGE");
            html_notify_text(html, MC_HN_STATUSTEXT, V_BSTR(&params->rgvarg[0]));
            break;

        case DISPID_TITLECHANGE:
            HTML_TRACE("dispatch_Invoke: DISPID_TITLECHANGE");
            html_notify_text(html, MC_HN_TITLETEXT, V_BSTR(&params->rgvarg[0]));
            break;

        case DISPID_COMMANDSTATECHANGE:
        {
            LONG cmd = V_I4(&params->rgvarg[1]);
            HTML_TRACE("dispatch_Invoke: DISPID_COMMANDSTATECHANGE");

            if(cmd == CSC_NAVIGATEBACK  ||  cmd == CSC_NAVIGATEFORWARD) {
                MC_NMHTMLHISTORY notify;
                BOOL enabled = (V_BOOL(&params->rgvarg[0]) != VARIANT_FALSE);

                if(cmd == CSC_NAVIGATEBACK)
                    html->can_back = enabled;
                else
                    html->can_forward = enabled;

                notify.hdr.hwndFrom = html->win;
                notify.hdr.idFrom = GetDlgCtrlID(html->win);
                notify.hdr.code = MC_HN_HISTORY;
                notify.bCanBack = html->can_back;
                notify.bCanForward = html->can_forward;
                MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, &notify);
            }
            break;
        }

        case DISPID_NEWWINDOW2:
        /* This is called instead of DISPID_NEWWINDOW3 on Windows XP SP2
         * and older. */
        {
            VARIANT_BOOL* cancel = V_BOOLREF(&params->rgvarg[0]);
            HTML_TRACE("dispatch_Invoke: DISPID_NEWWINDOW2");

            if(html_notify_text(html, MC_HN_NEWWINDOW, L"") == 0) {
                *cancel = VARIANT_TRUE;
                HTML_TRACE("dispatch_Invoke(DISPID_NEWWINDOW2): Canceled.");
            }
            break;
        }

        case DISPID_NEWWINDOW3:
        {
            BSTR url = V_BSTR(&params->rgvarg[0]);
            VARIANT_BOOL* cancel = V_BOOLREF(&params->rgvarg[3]);
            HTML_TRACE("dispatch_Invoke: DISPID_NEWWINDOW3");

            if(html_notify_text(html, MC_HN_NEWWINDOW, url) == 0) {
                *cancel = VARIANT_TRUE;
                HTML_TRACE("dispatch_Invoke(DISPID_NEWWINDOW3, '%S'): Canceled.", url);
            }
            break;
        }

        default:
            HTML_TRACE("dispatch_Invoke: unsupported disp_id %d", disp_id);
            return DISP_E_MEMBERNOTFOUND;
    }

    return S_OK;
}
Esempio n. 13
0
static LRESULT CALLBACK
html_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp)
{
    html_t* html = (html_t*) GetWindowLongPtr(win, 0);

    if(html != NULL  &&  html->ie_win == NULL) {
        /* Let's try to subclass IE window. This is very dirty hack,
         * which allows us to forward keyboard messages properly to
         * IOleInPlaceActiveObject::TranslateAccelerator().
         *
         * Normally this should be done from main app. loop but we do not
         * have it under control in the DLL. */
        html->ie_win = html_find_ie_window(win);
        if(html->ie_win != NULL) {
            HTML_TRACE("html_proc: Subclassing MSIE.");
            html->ie_proc = (WNDPROC) SetWindowLongPtr(html->ie_win,
                            GWLP_WNDPROC, (LONG_PTR) html_ie_subclass_proc);
            SetProp(html->ie_win, ie_prop, (HANDLE) html);

            if(GetFocus() == win) {
                SetFocus(html->ie_win);
                MC_SEND(html->ie_win, WM_LBUTTONDOWN, 0, 0);
                MC_SEND(html->ie_win, WM_LBUTTONUP, 0, 0);
            }
        }
    }

    switch(msg) {
        case MC_HM_GOTOURLW:
        case MC_HM_GOTOURLA:
        {
            int res = html_goto_url(html, (const void*)lp, (msg == MC_HM_GOTOURLW));
            return (res == 0 ? TRUE : FALSE);
        }

        case MC_HM_SETTAGCONTENTSW:
        case MC_HM_SETTAGCONTENTSA:
        {
            int res = html_set_element_contents(html, (void*)wp, (void*)lp,
                                                (msg == MC_HM_SETTAGCONTENTSW));
            return (res == 0 ? TRUE : FALSE);
        }

        case MC_HM_GOBACK:
        {
            int res = html_goto_back(html, wp);
            return (res == 0 ? TRUE : FALSE);
        }

        case MC_HM_CANBACK:
            return ((wp ? html->can_back : html->can_forward) ? TRUE : FALSE);

        case WM_SIZE:
        {
            IWebBrowser2* browser_iface;
            HRESULT hr;

            hr = html->browser_obj->lpVtbl->QueryInterface(html->browser_obj,
                        &IID_IWebBrowser2, (void**)&browser_iface);
            if(hr == S_OK  &&  browser_iface != NULL) {
                browser_iface->lpVtbl->put_Width(browser_iface, LOWORD(lp));
                browser_iface->lpVtbl->put_Height(browser_iface, HIWORD(lp));
                browser_iface->lpVtbl->Release(browser_iface);
            }
            return 0;
        }

        case WM_STYLECHANGED:
            if(wp == GWL_STYLE) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lp;
                html->style = ss->styleNew;
                RedrawWindow(win, NULL, NULL,
                             RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
            }
            break;

        case WM_NOTIFYFORMAT:
            switch(lp) {
                case NF_REQUERY:
                    html_notify_format(html);
                    return (html->unicode_notifications ? NFR_UNICODE : NFR_ANSI);
                case NF_QUERY:
                    return (MC_IS_UNICODE ? NFR_UNICODE : NFR_ANSI);
            }
            break;

        case CCM_SETUNICODEFORMAT:
        {
            BOOL tmp = html->unicode_notifications;
            html->unicode_notifications = (wp != 0);
            return tmp;
        }

        case CCM_GETUNICODEFORMAT:
            return html->unicode_notifications;

        case CCM_SETNOTIFYWINDOW:
        {
            HWND old = html->notify_win;
            html->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT));
            return (LPARAM) old;
        }

        case WM_SETFOCUS:
            if(html->ie_win) {
                SetFocus(html->ie_win);
                MC_SEND(html->ie_win, WM_LBUTTONDOWN, 0, 0);
                MC_SEND(html->ie_win, WM_LBUTTONUP, 0, 0);
            }
            return 0;

        case WM_GETDLGCODE:
            return DLGC_WANTALLKEYS;

        case WM_SETTEXT:
            return FALSE;

        case WM_GETTEXT:
            if(wp > 0)
                ((TCHAR*)lp)[0] = _T('\0');
            return 0;

        case WM_GETTEXTLENGTH:
            return 0;

        case WM_NCCREATE:
            html = html_nccreate(win, (CREATESTRUCT*)lp);
            if(MC_ERR(html == NULL))
                return FALSE;
            SetWindowLongPtr(win, 0, (LONG_PTR)html);
            return TRUE;

        case WM_CREATE:
            return (html_create(html, (CREATESTRUCT*)lp) == 0 ? 0 : -1);

        case WM_DESTROY:
            html_destroy(html);
            return 0;

        case WM_NCDESTROY:
            if(html)
                html_ncdestroy(html);
            return 0;
    }

    /* Forward keystrokes to the IE */
    if(WM_KEYFIRST <= msg  &&  msg <= WM_KEYLAST) {
        if(html->ie_win)
            MC_SEND(html->ie_win, msg, wp, lp);
        return 0;
    }

    return DefWindowProc(win, msg, wp, lp);
}
Esempio n. 14
0
File: grid.c Progetto: UIKit0/mctrl
static void
grid_paint(void* control, HDC dc, RECT* dirty, BOOL erase)
{
    grid_t* grid = (grid_t*) control;
    RECT client;
    RECT rect;
    int header_w, header_h;
    int old_dc_state;
    int col0, row0;
    int x0, y0;
    int col, row;
    int col_count = grid->col_count;
    int row_count = grid->row_count;
    table_t* table = grid->table;
    table_cell_t* cell;

    GRID_TRACE("grid_paint(%p, %d, %d, %d, %d)", grid,
               dirty->left, dirty->top, dirty->right, dirty->bottom);

    if(table == NULL  &&  !(grid->style & MC_GS_OWNERDATA))
        return;

    old_dc_state = SaveDC(dc);
    GetClientRect(grid->win, &client);
    header_w = grid_header_width(grid);
    header_h = grid_header_height(grid);

    if(grid->font != NULL)
        SelectObject(dc, grid->font);
    SetBkMode(dc, TRANSPARENT);
    SetTextColor(dc, RGB(0,0,0));
    SelectObject(dc, GetStockObject(BLACK_PEN));

    /* Find 1st visible column */
    rect.left = header_w - grid->scroll_x;
    for(col = 0; col < col_count; col++) {
        rect.right = rect.left + grid_col_width(grid, col);
        if(rect.right > header_w) {
            col0 = col;
            x0 = rect.left;
            break;
        }
        rect.left = rect.right;
    }

    /* Find 1st visible row */
    rect.top = header_h - grid->scroll_y;
    for(row = 0; row < row_count; row++) {
        rect.bottom = rect.top + grid_row_height(grid, row);
        if(rect.bottom > header_h) {
            row0 = row;
            y0 = rect.top;
            break;
        }
        rect.top = rect.bottom;
    }

    /* If needed, send MC_GN_ODCACHEHINT */
    if(grid->style & MC_GS_OWNERDATA) {
        WORD col1, row1;

        rect.right = x0;
        for(col1 = col0; col1+1 < grid->col_count; col1++) {
            rect.right += grid_col_width(grid, col1);
            if(rect.right >= client.right)
                break;
        }

        rect.bottom = y0;
        for(row1 = row0; row1+1 < grid->row_count; row1++) {
            rect.bottom += grid_row_height(grid, row1);
            if(rect.bottom >= client.bottom)
                break;
        }

        if(col0 != grid->cache_hint[0] || row0 != grid->cache_hint[1] ||
           col1 != grid->cache_hint[2] || row1 != grid->cache_hint[3]) {
            MC_NMGCACHEHINT hint;

            hint.hdr.hwndFrom = grid->win;
            hint.hdr.idFrom = GetWindowLong(grid->win, GWL_ID);
            hint.hdr.code = MC_GN_ODCACHEHINT;
            hint.wColumnFrom = col0;
            hint.wRowFrom = row0;
            hint.wColumnTo = col1;
            hint.wRowTo = row1;
            GRID_TRACE("grid_paint: Sending MC_GN_ODCACHEHINT (%hu, %hu, %hu, %hu)",
                       col0, row0, col1, row1);
            MC_SEND(grid->notify_win, WM_NOTIFY, hint.hdr.idFrom, &hint);

            grid->cache_hint[0] = col0;
            grid->cache_hint[1] = row0;
            grid->cache_hint[2] = col1;
            grid->cache_hint[3] = row1;
        }
    }

    /* Paint the "dead" top left header cell */
    if(header_w > 0  &&  header_h > 0  &&
       dirty->left < header_w  &&  dirty->top < header_h)
    {
        mc_rect_set(&rect, 0, 0, grid->header_width, grid->header_height);
        mc_clip_set(dc, 0, 0, MC_MIN(header_w, client.right), MC_MIN(header_h, client.bottom));
        grid_paint_header_cell(grid, MC_TABLE_HEADER, MC_TABLE_HEADER, NULL, dc, &rect, -1, 0);
    }

    /* Paint column headers */
    if(header_h > 0  &&  dirty->top < header_h) {
        rect.left = x0;
        rect.top = 0;
        rect.bottom = header_h;

        for(col = col0; col < col_count; col++) {
            rect.right = rect.left + grid_col_width(grid, col);
            mc_clip_set(dc, MC_MAX(header_w, rect.left), rect.top,
                        MC_MIN(rect.right, client.right), MC_MIN(rect.bottom, client.bottom));
            grid_paint_header_cell(grid, col, MC_TABLE_HEADER, (table ? &table->cols[col] : NULL),
                                   dc, &rect, col, (grid->style & MC_GS_COLUMNHEADERMASK));
            rect.left = rect.right;
            if(rect.right >= client.right)
                break;
        }
    }

    /* Paint row headers */
    if(header_w > 0  &&  dirty->left <= header_w) {
        rect.left = 0;
        rect.top = y0;
        rect.right = header_w;

        for(row = row0; row < row_count; row++) {
            rect.bottom = rect.top + grid_row_height(grid, row);
            mc_clip_set(dc, rect.left, MC_MAX(header_h, rect.top),
                        MC_MIN(rect.right, client.right), MC_MIN(rect.bottom, client.bottom));
            grid_paint_header_cell(grid, MC_TABLE_HEADER, row, (table ? &table->rows[row] : NULL),
                                   dc, &rect, row, (grid->style & MC_GS_ROWHEADERMASK));
            rect.top = rect.bottom;
            if(rect.bottom >= client.bottom)
                break;
        }
    }

    /* Paint grid lines */
    if(!(grid->style & MC_GS_NOGRIDLINES)) {
        HPEN pen, old_pen;
        int x, y;

        mc_clip_set(dc, header_w, header_h, client.right, client.bottom);
        pen = CreatePen(PS_SOLID, 0, mcGetThemeSysColor(grid->theme_listview, COLOR_3DFACE));
        old_pen = SelectObject(dc, pen);

        x = x0;
        y = header_h + grid->scroll_y_max - grid->scroll_y;
        for(col = col0; col < col_count; col++) {
            x += grid_col_width(grid, col);
            MoveToEx(dc, x-1, header_h, NULL);
            LineTo(dc, x-1, y);
            if(x >= client.right)
                break;
        }

        x = header_w + grid->scroll_x_max - grid->scroll_x;
        y = y0;
        for(row = 0; row < row_count; row++) {
            y += grid_row_height(grid, row);
            MoveToEx(dc, header_w, y-1, NULL);
            LineTo(dc, x, y-1);
            if(y >= client.bottom)
                break;
        }

        SelectObject(dc, old_pen);
        DeleteObject(pen);
    }

    /* Paint grid cells */
    rect.top = y0;
    for(row = row0; row < row_count; row++) {
        rect.bottom = rect.top + grid_row_height(grid, row);
        rect.left = x0;
        for(col = col0; col < col_count; col++) {
            if(table != NULL)
                cell = table_cell(table, col, row);
            else
                cell = NULL;
            rect.right = rect.left + grid_col_width(grid, col);
            grid_paint_cell(grid, col, row, cell, dc, &rect);
            if(rect.right >= client.right)
                break;
            rect.left = rect.right;
        }
        if(rect.bottom >= client.bottom)
            break;
        rect.top = rect.bottom;
    }

    RestoreDC(dc, old_dc_state);
}
Esempio n. 15
0
File: grid.c Progetto: UIKit0/mctrl
static void
grid_get_dispinfo(grid_t* grid, WORD col, WORD row, table_cell_t* cell,
                  grid_dispinfo_t* di, DWORD mask)
{
    MC_NMGDISPINFO info;

    MC_ASSERT((mask & ~(MC_TCMF_TEXT | MC_TCMF_VALUE | MC_TCMF_FLAGS)) == 0);

    /* Use what can be taken from the cell. */
    if(cell != NULL) {
        if(cell->text != MC_LPSTR_TEXTCALLBACK) {
            di->text = (cell->is_value ? NULL : cell->text);
            mask &= ~MC_TCMF_TEXT;
        }

        di->value = (cell->is_value ? cell->value : NULL);
        di->flags = cell->flags;
        mask &= ~(MC_TCMF_VALUE | MC_TCMF_FLAGS);

        if(mask == 0)
            return;
    }

    /* For the rest data, fire MC_GN_GETDISPINFO notification. */
    info.hdr.hwndFrom = grid->win;
    info.hdr.idFrom = GetWindowLong(grid->win, GWL_ID);
    info.hdr.code = (grid->unicode_notifications ? MC_GN_GETDISPINFOW : MC_GN_GETDISPINFOA);
    info.wColumn = col;
    info.wRow = row;
    info.cell.fMask = mask;
    /* Set info.cell members to meaningful values. lParam may be needed by the
     * app to find the requested data. Other members should be set to some
     * defaults to deal with broken apps which do not set the asked members. */
    if(cell != NULL) {
        info.cell.pszText = NULL;
        info.cell.hValue = NULL;
        info.cell.lParam = cell->lp;
        info.cell.dwFlags = cell->flags;
    } else {
        info.cell.pszText = NULL;
        info.cell.hValue = NULL;
        info.cell.lParam = 0;
        info.cell.dwFlags = 0;
    }
    MC_SEND(grid->notify_win, WM_NOTIFY, 0, &info);

    /* If needed, convert the text from parent to the expected format. */
    if(mask & MC_TCMF_TEXT) {
        if(grid->unicode_notifications == MC_IS_UNICODE)
            di->text = info.cell.pszText;
        else
            di->text = mc_str(info.cell.pszText, (grid->unicode_notifications ? MC_STRW : MC_STRA), MC_STRT);
    } else {
        /* Needed even when not asked for because of grid_free_dispinfo() */
        di->text = NULL;
    }

    /* Small optimization: We do not ask about the corresponding bits in the
     * mask for these. If not set, the assignment does no hurt and we save few
     * instructions. */
    di->value = info.cell.hValue;
    di->flags = info.cell.dwFlags;
}