<commit_before>// Copyright (c) 2013 Joshua Beitler, Mirus contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <term/terminal.hpp>

// terminal sizes
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 24;

// term info
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;

uint8_t mirus::make_color(enum vga_color fg, enum vga_color bg) {
    return fg | bg << 4;
}

uint16_t mirus::make_vgaentry(char c, uint8_t color) {
    uint16_t c16 = c;
    uint16_t color16 = color;

    return c16 | color16 << 8;
}

void mirus::terminal_initialize() {
    using namespace mirus;

    terminal_row = 0;
    terminal_column = 0;
    terminal_color = make_color(COLOR_WHITE, COLOR_BLACK);
    terminal_buffer = (uint16_t*) 0xB8000;

    for ( size_t y = 0; y < VGA_HEIGHT; y++ )
    {
        for ( size_t x = 0; x < VGA_WIDTH; x++ )
        {
            const size_t index = y * VGA_WIDTH + x;
            terminal_buffer[index] = make_vgaentry(' ', terminal_color);
        }
    }
}

// set color
void mirus::terminal_setcolor(uint8_t color) {
    terminal_color = color;
}

// put an entry at location
void mirus::terminal_putentryat(char c, uint8_t color, size_t x, size_t y) {
    using namespace mirus;

    const size_t index = y * VGA_WIDTH + x;
    terminal_buffer[index] = make_vgaentry(c, color);
}

// put a char at a location
void mirus::terminal_putchar(char c) {
    using namespace mirus;

    if (c == '\r') {
        ++terminal_row;
        terminal_column = 0;
    } else if (c == '\b') {
        --terminal_column;
    }

    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);

    if ( ++terminal_column == VGA_WIDTH )
    {
        terminal_column = 0;
        terminal_row++;

        // if (++terminal_row == 25)
        // {
        //     terminal_scroll();
        // }
    }

    // TODO: bug here
    // if (++terminal_row == VGA_HEIGHT) {
    //     terminal_scroll();
    // }

    terminal_move_cursor();
}

void mirus::terminal_putchar(char c, uint8_t color) {
    uint8_t oldcolor = terminal_color;
    terminal_setcolor(color);
    mirus::terminal_putchar(c);
    terminal_setcolor(oldcolor);
}

// write a string
void mirus::terminal_writestring(const char* data) {
    using namespace mirus;

    size_t datalen = strlen(data);

    for (size_t i = 0; i < datalen; i++)
        terminal_putchar(data[i]);
}

void mirus::terminal_writestring(const char* data, uint8_t color) {
    using namespace mirus;

    size_t datalen = strlen(data);
    for (size_t i = 0; i < datalen; i++)
        terminal_putchar(data[i], color);
}

void mirus::terminal_clear() {
    using namespace mirus;

    uint8_t attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
    uint16_t blank = 0x20 /* space */ | (attributeByte << 8);

    for (int i = 0; i < 80 * 25; i++)
        terminal_buffer[i] = 0;

    // Move the hardware cursor back to the start.
    terminal_row = 0;
    terminal_column = 0;

    terminal_move_cursor();
}

// TODO: does not scroll correctly
void mirus::terminal_scroll() {
    using namespace mirus;

    uint8_t blank = make_color(COLOR_BLACK, COLOR_BLACK);
    unsigned temp;
    unsigned short* vidmem = nullptr;

    vidmem = (unsigned short*)0xB8000;

    temp = terminal_column - 25 + 1;

    mirus::memcpy(vidmem, vidmem + temp * 80, (25 - temp) * 80 * 2);
    mirus::memsetw(vidmem + (25 - temp) * 80, blank, 80);

    terminal_column = 25 - 1;
}

void mirus::terminal_move_cursor() {
    using namespace mirus;

    unsigned temp;

    /* The equation for finding the index in a linear
    *  chunk of memory can be represented by:
    *  Index = [(y * width) + x] */
    temp = terminal_row * 80 + terminal_column;

    /* This sends a command to indicies 14 and 15 in the
    *  CRT Control Register of the VGA controller. These
    *  are the high and low bytes of the index that show
    *  where the hardware cursor is to be 'blinking'. To
    *  learn more, you should look up some VGA specific
    *  programming documents. A great start to graphics:
    *  http://www.brackeen.com/home/vga */
    mirus::outb(0x3D4, 14);
    mirus::outb(0x3D5, temp >> 8);
    mirus::outb(0x3D4, 15);
    mirus::outb(0x3D5, temp);
}<commit_msg>Backspace?<commit_after>// Copyright (c) 2013 Joshua Beitler, Mirus contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <term/terminal.hpp>

// terminal sizes
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 24;

// term info
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;

uint8_t mirus::make_color(enum vga_color fg, enum vga_color bg) {
    return fg | bg << 4;
}

uint16_t mirus::make_vgaentry(char c, uint8_t color) {
    uint16_t c16 = c;
    uint16_t color16 = color;

    return c16 | color16 << 8;
}

void mirus::terminal_initialize() {
    using namespace mirus;

    terminal_row = 0;
    terminal_column = 0;
    terminal_color = make_color(COLOR_WHITE, COLOR_BLACK);
    terminal_buffer = (uint16_t*) 0xB8000;

    for ( size_t y = 0; y < VGA_HEIGHT; y++ )
    {
        for ( size_t x = 0; x < VGA_WIDTH; x++ )
        {
            const size_t index = y * VGA_WIDTH + x;
            terminal_buffer[index] = make_vgaentry(' ', terminal_color);
        }
    }
}

// set color
void mirus::terminal_setcolor(uint8_t color) {
    terminal_color = color;
}

// put an entry at location
void mirus::terminal_putentryat(char c, uint8_t color, size_t x, size_t y) {
    using namespace mirus;

    const size_t index = y * VGA_WIDTH + x;
    terminal_buffer[index] = make_vgaentry(c, color);
}

// put a char at a location
void mirus::terminal_putchar(char c) {
    using namespace mirus;

    // if (c == '\r') {
    //     ++terminal_row;
    //     terminal_column = 0;
    // } else if (c == '\b') {
    //     --terminal_column;
    // }

    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);

    if ( ++terminal_column == VGA_WIDTH )
    {
        terminal_column = 0;
        terminal_row++;

        // if (++terminal_row == 25)
        // {
        //     terminal_scroll();
        // }
    }

    // TODO: bug here
    // if (++terminal_row == VGA_HEIGHT) {
    //     terminal_scroll();
    // }

    terminal_move_cursor();
}

void mirus::terminal_putchar(char c, uint8_t color) {
    uint8_t oldcolor = terminal_color;
    terminal_setcolor(color);
    mirus::terminal_putchar(c);
    terminal_setcolor(oldcolor);
}

// write a string
void mirus::terminal_writestring(const char* data) {
    using namespace mirus;

    size_t datalen = strlen(data);

    for (size_t i = 0; i < datalen; i++) {
        if (data[i] == '\r') {
            ++terminal_column;
            terinal_row = 0;
        } else if (data[i] == '\b') {
            terminal_column--;
        } else
            terminal_putchar(data[i]);
    }
}

void mirus::terminal_writestring(const char* data, uint8_t color) {
    using namespace mirus;

    size_t datalen = strlen(data);
    for (size_t i = 0; i < datalen; i++) {
        if (data[i] == '\r') {
            ++terminal_column;
            terminal_row = 0;
        }  else if (data[i] == '\b') {
            terminal_column--;
        } else
            terminal_putchar(data[i], color);
    }
}

void mirus::terminal_clear() {
    using namespace mirus;

    uint8_t attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
    uint16_t blank = 0x20 /* space */ | (attributeByte << 8);

    for (int i = 0; i < 80 * 25; i++)
        terminal_buffer[i] = 0;

    // Move the hardware cursor back to the start.
    terminal_row = 0;
    terminal_column = 0;

    terminal_move_cursor();
}

// TODO: does not scroll correctly
void mirus::terminal_scroll() {
    using namespace mirus;

    uint8_t blank = make_color(COLOR_BLACK, COLOR_BLACK);
    unsigned temp;
    unsigned short* vidmem = nullptr;

    vidmem = (unsigned short*)0xB8000;

    temp = terminal_column - 25 + 1;

    mirus::memcpy(vidmem, vidmem + temp * 80, (25 - temp) * 80 * 2);
    mirus::memsetw(vidmem + (25 - temp) * 80, blank, 80);

    terminal_column = 25 - 1;
}

void mirus::terminal_move_cursor() {
    using namespace mirus;

    unsigned temp;

    /* The equation for finding the index in a linear
    *  chunk of memory can be represented by:
    *  Index = [(y * width) + x] */
    temp = terminal_row * 80 + terminal_column;

    /* This sends a command to indicies 14 and 15 in the
    *  CRT Control Register of the VGA controller. These
    *  are the high and low bytes of the index that show
    *  where the hardware cursor is to be 'blinking'. To
    *  learn more, you should look up some VGA specific
    *  programming documents. A great start to graphics:
    *  http://www.brackeen.com/home/vga */
    mirus::outb(0x3D4, 14);
    mirus::outb(0x3D5, temp >> 8);
    mirus::outb(0x3D4, 15);
    mirus::outb(0x3D5, temp);
}<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2019 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef BFLOAT16_DEVICE_HPP
#define BFLOAT16_DEVICE_HPP

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __HIP_PLATFORM_HCC__
#define EXECUTION_SPECIFIER __device__
#else
#define EXECUTION_SPECIFIER
#endif // MIOPEN_BACKEND_HIP

typedef union
{
    uint u32;
    ushort2 ushortx2;

// Composable kernels are written in HIP language. The language doesnt support
// ushort2.hi or ushort2.low.
#ifdef __HIP_PLATFORM_HCC__
    ushort ushortvec[2];
#endif // MIOPEN_BACKEND_HIP
    float f32;
} cvt_bf16_fp32_t;

EXECUTION_SPECIFIER float bfloat16_to_float(ushort src_val)
{
    cvt_bf16_fp32_t target_val;

#ifdef __HIP_PLATFORM_HCC__
    target_val.ushortx2 = make_ushort2(0, src_val);
#else
    target_val.ushortx2 = (ushort2)(0, src_val);
#endif

    return target_val.f32;
}

EXECUTION_SPECIFIER ushort float_to_bfloat16(float src_val)
{
    cvt_bf16_fp32_t target_val;
    target_val.f32 = src_val;
    // BF16 round and NaN preservation code matches
    // https://github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/library/include/rocblas_bfloat16.h
    if((~target_val.u32 & 0x7f800000) == 0) // Inf or NaN
    {
        // When all of the exponent bits are 1, the value is Inf or NaN.
        // Inf is indicated by a zero mantissa. NaN is indicated by any nonzero
        // mantissa bit. Quiet NaN is indicated by the most significant mantissa
        // bit being 1. Signaling NaN is indicated by the most significant
        // mantissa bit being 0 but some other bit(s) being 1. If any of the
        // lower 16 bits of the mantissa are 1, we set the least significant bit
        // of the bfloat16 mantissa, in order to preserve signaling NaN in case
        // the bloat16's mantissa bits are all 0.
        if((target_val.u32 & 0xffff) != 0)
        {
            target_val.u32 |= 0x10000; // Preserve signaling NaN
        }
    }
    else
    {
#ifdef MIOPEN_USE_RNE_BFLOAT16
// When the exponent bits are not all 1s, then the value is zero, normal,
// or subnormal. We round the bfloat16 mantissa up by adding 0x7FFF, plus
// 1 if the least significant bit of the bfloat16 mantissa is 1 (odd).
// This causes the bfloat16's mantissa to be incremented by 1 if the 16
// least significant bits of the float mantissa are greater than 0x8000,
// or if they are equal to 0x8000 and the least significant bit of the
// bfloat16 mantissa is 1 (odd). This causes it to be rounded to even when
// the lower 16 bits are exactly 0x8000. If the bfloat16 mantissa already
// has the value 0x7f, then incrementing it causes it to become 0x00 and
// the exponent is incremented by one, which is the next higher FP value
// to the unrounded bfloat16 value. When the bfloat16 value is subnormal
// with an exponent of 0x00 and a mantissa of 0x7F, it may be rounded up
// to a normal value with an exponent of 0x01 and a mantissa of 0x00.
// When the bfloat16 value has an exponent of 0xFE and a mantissa of 0x7F,
// incrementing it causes it to become an exponent of 0xFF and a mantissa
// of 0x00, which is Inf, the next higher value to the unrounded value.
#ifdef __HIP_PLATFORM_HCC__
        target_val.u32 += (0x7fff + (target_val.ushortvec[1] & 1));
#else
        target_val.u32 +=
            (0x7fff + (target_val.ushortx2.hi & 1)); // Round to nearest, round to even
#endif // MIOPEN_BACKEND_HIP
#endif // MIOPEN_USE_RNE_BFLOAT16
    }

#ifdef __HIP_PLATFORM_HCC__
    return target_val.ushortvec[1];
#else
    return target_val.ushortx2.hi;
#endif // MIOPEN_BACKEND_HIP
}

#ifdef __cplusplus
}
#endif

#endif // BFLOAT16_DEVICE_HPP
<commit_msg>Resolves hipclang compilation error pertaining to anonymous union (#157)<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2019 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef BFLOAT16_DEVICE_HPP
#define BFLOAT16_DEVICE_HPP

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __HIP_PLATFORM_HCC__
#define EXECUTION_SPECIFIER __device__
#else
#define EXECUTION_SPECIFIER
#endif // MIOPEN_BACKEND_HIP

typedef union cvt_bf16_fp32
{
    uint u32;
    ushort2 ushortx2;

// Composable kernels are written in HIP language. The language doesnt support
// ushort2.hi or ushort2.low.
#ifdef __HIP_PLATFORM_HCC__
    ushort ushortvec[2];
#endif // MIOPEN_BACKEND_HIP
    float f32;
} cvt_bf16_fp32_t;

EXECUTION_SPECIFIER float bfloat16_to_float(ushort src_val)
{
    cvt_bf16_fp32_t target_val;

#ifdef __HIP_PLATFORM_HCC__
    target_val.ushortx2 = make_ushort2(0, src_val);
#else
    target_val.ushortx2 = (ushort2)(0, src_val);
#endif

    return target_val.f32;
}

EXECUTION_SPECIFIER ushort float_to_bfloat16(float src_val)
{
    cvt_bf16_fp32_t target_val;
    target_val.f32 = src_val;
    // BF16 round and NaN preservation code matches
    // https://github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/library/include/rocblas_bfloat16.h
    if((~target_val.u32 & 0x7f800000) == 0) // Inf or NaN
    {
        // When all of the exponent bits are 1, the value is Inf or NaN.
        // Inf is indicated by a zero mantissa. NaN is indicated by any nonzero
        // mantissa bit. Quiet NaN is indicated by the most significant mantissa
        // bit being 1. Signaling NaN is indicated by the most significant
        // mantissa bit being 0 but some other bit(s) being 1. If any of the
        // lower 16 bits of the mantissa are 1, we set the least significant bit
        // of the bfloat16 mantissa, in order to preserve signaling NaN in case
        // the bloat16's mantissa bits are all 0.
        if((target_val.u32 & 0xffff) != 0)
        {
            target_val.u32 |= 0x10000; // Preserve signaling NaN
        }
    }
    else
    {
#ifdef MIOPEN_USE_RNE_BFLOAT16
// When the exponent bits are not all 1s, then the value is zero, normal,
// or subnormal. We round the bfloat16 mantissa up by adding 0x7FFF, plus
// 1 if the least significant bit of the bfloat16 mantissa is 1 (odd).
// This causes the bfloat16's mantissa to be incremented by 1 if the 16
// least significant bits of the float mantissa are greater than 0x8000,
// or if they are equal to 0x8000 and the least significant bit of the
// bfloat16 mantissa is 1 (odd). This causes it to be rounded to even when
// the lower 16 bits are exactly 0x8000. If the bfloat16 mantissa already
// has the value 0x7f, then incrementing it causes it to become 0x00 and
// the exponent is incremented by one, which is the next higher FP value
// to the unrounded bfloat16 value. When the bfloat16 value is subnormal
// with an exponent of 0x00 and a mantissa of 0x7F, it may be rounded up
// to a normal value with an exponent of 0x01 and a mantissa of 0x00.
// When the bfloat16 value has an exponent of 0xFE and a mantissa of 0x7F,
// incrementing it causes it to become an exponent of 0xFF and a mantissa
// of 0x00, which is Inf, the next higher value to the unrounded value.
#ifdef __HIP_PLATFORM_HCC__
        target_val.u32 += (0x7fff + (target_val.ushortvec[1] & 1));
#else
        target_val.u32 +=
            (0x7fff + (target_val.ushortx2.hi & 1)); // Round to nearest, round to even
#endif // MIOPEN_BACKEND_HIP
#endif // MIOPEN_USE_RNE_BFLOAT16
    }

#ifdef __HIP_PLATFORM_HCC__
    return target_val.ushortvec[1];
#else
    return target_val.ushortx2.hi;
#endif // MIOPEN_BACKEND_HIP
}

#ifdef __cplusplus
}
#endif

#endif // BFLOAT16_DEVICE_HPP
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qquicklayout_p.h"
#include <QEvent>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qnumeric.h>
#include <limits>

/*!
    \qmltype Layout
    \instantiates QQuickLayoutAttached
    \inqmlmodule QtQuick.Layouts
    \ingroup layouts
    \brief Provides attached properties for items pushed onto a \l GridLayout,
    \l RowLayout or \l ColumnLayout.

    An object of type Layout is attached to children of the layout to provide layout specific
    information about the item.
    The properties of the attached object influences how the layout will arrange the items.

    For instance, you can specify \l minimumWidth, \l preferredWidth, and
    \l maximumWidth if the default values are not satisfactory.

    When a layout is resized, items may grow or shrink. Due to this, items have a
    \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a
    \l{Layout::maximumWidth}{maximum size}.

    If minimum size have not been explicitly specified on an item, the size is set to \c 0.
    If maximum size have not been explicitly specified on an item, the size is set to
    \c Number.POSITIVE_INFINITY.

    For layouts, the implicit minimum and maximum size depends on the content of the layouts.

    The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If it is \c
    false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink
    between its minimum and maximum size as the layout is resized.

    \note It is not recommended to have bindings to the x, y, width, or height properties of items
    in a layout, since this would conflict with the goal of the Layout, and also cause binding
    loops.

    \sa GridLayout
    \sa RowLayout
    \sa ColumnLayout
*/

QT_BEGIN_NAMESPACE

QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
    : QObject(parent),
      m_minimumWidth(0),
      m_minimumHeight(0),
      m_preferredWidth(-1),
      m_preferredHeight(-1),
      m_maximumWidth(std::numeric_limits<qreal>::infinity()),
      m_maximumHeight(std::numeric_limits<qreal>::infinity()),
      m_row(-1),
      m_column(-1),
      m_rowSpan(1),
      m_columnSpan(1),
      m_fillWidth(false),
      m_fillHeight(false),
      m_isFillWidthSet(false),
      m_isFillHeightSet(false),
      m_isMinimumWidthSet(false),
      m_isMinimumHeightSet(false),
      m_isMaximumWidthSet(false),
      m_isMaximumHeightSet(false),
      m_changesNotificationEnabled(true),
      m_alignment(0)
{

}

/*!
    \qmlattachedproperty real Layout::minimumWidth

    This property holds the maximum width of an item in a layout.
    The default value is the items implicit minimum width.

    If the item is a layout, the implicit minimum width will be the minimum width the layout can
    have without any of its items shrink beyond their minimum width.
    The implicit minimum width for any other item is \c 0.

    Setting this value to -1 will reset the width back to its implicit minimum width.

    \sa preferredWidth
    \sa maximumWidth
*/
void QQuickLayoutAttached::setMinimumWidth(qreal width)
{
    if (qIsNaN(width))
        return;
    m_isMinimumWidthSet = width >= 0;
    if (m_minimumWidth == width)
        return;

    m_minimumWidth = width;
    invalidateItem();
    emit minimumWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::minimumHeight

    The default value is the items implicit minimum height.

    If the item is a layout, the implicit minimum height will be the minimum height the layout can
    have without any of its items shrink beyond their minimum height.
    The implicit minimum height for any other item is \c 0.

    Setting this value to -1 will reset the height back to its implicit minimum height.

    \sa preferredHeight
    \sa maximumHeight
*/
void QQuickLayoutAttached::setMinimumHeight(qreal height)
{
    if (qIsNaN(height))
        return;
    m_isMinimumHeightSet = height >= 0;
    if (m_minimumHeight == height)
        return;

    m_minimumHeight = height;
    invalidateItem();
    emit minimumHeightChanged();
}

/*!
    \qmlattachedproperty real Layout::preferredWidth

    This property holds the preferred width of an item in a layout.
    If the preferred width is -1 it will be ignored, and the layout
    will use \l{Item::implicitWidth}{implicitWidth} instead.
    The default is \c -1.

    \sa minimumWidth
    \sa maximumWidth
*/
void QQuickLayoutAttached::setPreferredWidth(qreal width)
{
    if (qIsNaN(width) || m_preferredWidth == width)
        return;

    m_preferredWidth = width;
    invalidateItem();
    emit preferredWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::preferredHeight

    This property holds the preferred height of an item in a layout.
    If the preferred height is -1 it will be ignored, and the layout
    will use \l{Item::implicitHeight}{implicitHeight} instead.
    The default is \c -1.

    \sa minimumHeight
    \sa maximumHeight
*/
void QQuickLayoutAttached::setPreferredHeight(qreal height)
{
    if (qIsNaN(height) || m_preferredHeight == height)
        return;

    m_preferredHeight = height;
    invalidateItem();
    emit preferredHeightChanged();
}

/*!
    \qmlattachedproperty real Layout::maximumWidth

    This property holds the maximum width of an item in a layout.
    The default value is the items implicit maximum width.

    If the item is a layout, the implicit maximum width will be the maximum width the layout can
    have without any of its items grow beyond their maximum width.
    The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY.

    Setting this value to -1 will reset the width back to its implicit maximum width.

    \sa minimumWidth
    \sa preferredWidth
*/
void QQuickLayoutAttached::setMaximumWidth(qreal width)
{
    if (qIsNaN(width))
        return;
    m_isMaximumWidthSet = width >= 0;
    if (m_maximumWidth == width)
        return;

    m_maximumWidth = width;
    invalidateItem();
    emit maximumWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::maximumHeight

    The default value is the items implicit maximum height.

    If the item is a layout, the implicit maximum height will be the maximum height the layout can
    have without any of its items grow beyond their maximum height.
    The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY.

    Setting this value to -1 will reset the height back to its implicit maximum height.

    \sa minimumHeight
    \sa preferredHeight
*/
void QQuickLayoutAttached::setMaximumHeight(qreal height)
{
    if (qIsNaN(height))
        return;
    m_isMaximumHeightSet = height >= 0;
    if (m_maximumHeight == height)
        return;

    m_maximumHeight = height;
    invalidateItem();
    emit maximumHeightChanged();
}

void QQuickLayoutAttached::setMinimumImplicitSize(const QSizeF &sz)
{
    bool emitWidthChanged = false;
    bool emitHeightChanged = false;
    if (!m_isMinimumWidthSet && m_minimumWidth != sz.width()) {
        m_minimumWidth = sz.width();
        emitWidthChanged = true;
    }
    if (!m_isMinimumHeightSet && m_minimumHeight != sz.height()) {
        m_minimumHeight = sz.height();
        emitHeightChanged = true;
    }
    // Only invalidate the item once, and make sure we emit signal changed after the call to
    // invalidateItem()
    if (emitWidthChanged || emitHeightChanged) {
        invalidateItem();
        if (emitWidthChanged)
            emit minimumWidthChanged();
        if (emitHeightChanged)
            emit minimumHeightChanged();
    }
}

void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz)
{
    bool emitWidthChanged = false;
    bool emitHeightChanged = false;
    if (!m_isMaximumWidthSet && m_maximumWidth != sz.width()) {
        m_maximumWidth = sz.width();
        emitWidthChanged = true;
    }
    if (!m_isMaximumHeightSet && m_maximumHeight != sz.height()) {
        m_maximumHeight = sz.height();
        emitHeightChanged = true;
    }
    // Only invalidate the item once, and make sure we emit changed signal after the call to
    // invalidateItem()
    if (emitWidthChanged || emitHeightChanged) {
        invalidateItem();
        if (emitWidthChanged)
            emit maximumWidthChanged();
        if (emitHeightChanged)
            emit maximumHeightChanged();
    }
}

/*!
    \qmlattachedproperty bool Layout::fillWidth

    If this property is \c true, the item will be as wide as possible while respecting
    the given constraints. If the property is \c false, the item will have a fixed width
    set to the preferred width.
    The default is \c false, except for layouts themselves which defaults to \c true.

    \sa fillHeight
*/
void QQuickLayoutAttached::setFillWidth(bool fill)
{
    m_isFillWidthSet = true;
    if (m_fillWidth != fill) {
        m_fillWidth = fill;
        invalidateItem();
        emit fillWidthChanged();
    }
}

/*!
    \qmlattachedproperty bool Layout::fillHeight

    If this property is \c true, the item will be as tall as possible while respecting
    the given constraints. If the property is \c false, the item will have a fixed height
    set to the preferred height.
    The default is \c false, except for layouts themselves which defaults to \c true.

    \sa fillWidth
*/
void QQuickLayoutAttached::setFillHeight(bool fill)
{
    m_isFillHeightSet = true;
    if (m_fillHeight != fill) {
        m_fillHeight = fill;
        invalidateItem();
        emit fillHeightChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::row

    This property allows you to specify the row position of an item in a \l GridLayout.

    If both \l column and this property are not set, it is up to the layout to assign a cell to the item.

    The default value is \c 0.

    \sa column
    \sa rowSpan
*/
void QQuickLayoutAttached::setRow(int row)
{
    if (row >= 0 && row != m_row) {
        m_row = row;
        repopulateLayout();
        emit rowChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::column

    This property allows you to specify the column position of an item in a \l GridLayout.

    If both \l row and this property are not set, it is up to the layout to assign a cell to the item.

    The default value is \c 0.

    \sa row
    \sa columnSpan
*/
void QQuickLayoutAttached::setColumn(int column)
{
    if (column >= 0 && column != m_column) {
        m_column = column;
        repopulateLayout();
        emit columnChanged();
    }
}

/*!
    \qmlattachedproperty Qt.Alignment Layout::alignment

    This property allows you to specify the alignment of an item within the cell(s) it occupies.

    The default value is \c 0, which means it will be \c{Qt.AlignVCenter | Qt.AlignLeft}

    A valid alignment is a combination of the following flags:
    \list
    \li Qt::AlignLeft
    \li Qt::AlignHCenter
    \li Qt::AlignRight
    \li Qt::AlignTop
    \li Qt::AlignVCenter
    \li Qt::AlignBottom
    \li Qt::AlignBaseline
    \endlist

*/
void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
{
    if (align != m_alignment) {
        m_alignment = align;
        if (QQuickLayout *layout = parentLayout()) {
            layout->setAlignment(item(), align);
            invalidateItem();
        }
        emit alignmentChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::rowSpan

    This property allows you to specify the row span of an item in a \l GridLayout.

    The default value is \c 1.

    \sa columnSpan
    \sa row
*/
void QQuickLayoutAttached::setRowSpan(int span)
{
    if (span != m_rowSpan) {
        m_rowSpan = span;
        repopulateLayout();
        emit rowSpanChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::columnSpan

    This property allows you to specify the column span of an item in a \l GridLayout.

    The default value is \c 1.

    \sa rowSpan
    \sa column
*/
void QQuickLayoutAttached::setColumnSpan(int span)
{
    if (span != m_columnSpan) {
        m_columnSpan = span;
        repopulateLayout();
        emit columnSpanChanged();
    }
}

qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const
{
    qreal result = 0;
    if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) {
        const QSizeF sz = layout->sizeHint(which);
        result = (orientation == Qt::Horizontal ? sz.width() : sz.height());
    } else {
        if (which == Qt::MaximumSize)
            result = std::numeric_limits<qreal>::infinity();
    }
    return result;
}

void QQuickLayoutAttached::invalidateItem()
{
    if (!m_changesNotificationEnabled)
        return;
    quickLayoutDebug() << "QQuickLayoutAttached::invalidateItem";
    if (QQuickLayout *layout = parentLayout()) {
        layout->invalidate(item());
    }
}

void QQuickLayoutAttached::repopulateLayout()
{
    if (QQuickLayout *layout = parentLayout())
        layout->updateLayoutItems();
}

QQuickLayout *QQuickLayoutAttached::parentLayout() const
{
    QQuickItem *parentItem = item();
    if (parentItem) {
        parentItem = parentItem->parentItem();
        return qobject_cast<QQuickLayout *>(parentItem);
    } else {
        qWarning("Layout must be attached to Item elements");
    }
    return 0;
}

QQuickItem *QQuickLayoutAttached::item() const
{
    return qobject_cast<QQuickItem *>(parent());
}

QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
    : QQuickItem(dd, parent),
      m_dirty(false)
{
}

QQuickLayout::~QQuickLayout()
{

}

QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
{
    return new QQuickLayoutAttached(object);
}

void QQuickLayout::updatePolish()
{
    rearrange(QSizeF(width(), height()));
}

void QQuickLayout::componentComplete()
{
    QQuickItem::componentComplete();
}

void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
{
    if (m_dirty)
        return;

    m_dirty = true;

    if (!qobject_cast<QQuickLayout *>(parentItem())) {
        quickLayoutDebug() << "QQuickLayout::invalidate(), polish()";
        polish();
    }
}

void QQuickLayout::rearrange(const QSizeF &/*size*/)
{
    m_dirty = false;
}

QT_END_NAMESPACE
<commit_msg>Fix grammar in Layout::fillWidth and Layout::fillHeight documentation.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qquicklayout_p.h"
#include <QEvent>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qnumeric.h>
#include <limits>

/*!
    \qmltype Layout
    \instantiates QQuickLayoutAttached
    \inqmlmodule QtQuick.Layouts
    \ingroup layouts
    \brief Provides attached properties for items pushed onto a \l GridLayout,
    \l RowLayout or \l ColumnLayout.

    An object of type Layout is attached to children of the layout to provide layout specific
    information about the item.
    The properties of the attached object influences how the layout will arrange the items.

    For instance, you can specify \l minimumWidth, \l preferredWidth, and
    \l maximumWidth if the default values are not satisfactory.

    When a layout is resized, items may grow or shrink. Due to this, items have a
    \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a
    \l{Layout::maximumWidth}{maximum size}.

    If minimum size have not been explicitly specified on an item, the size is set to \c 0.
    If maximum size have not been explicitly specified on an item, the size is set to
    \c Number.POSITIVE_INFINITY.

    For layouts, the implicit minimum and maximum size depends on the content of the layouts.

    The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If it is \c
    false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink
    between its minimum and maximum size as the layout is resized.

    \note It is not recommended to have bindings to the x, y, width, or height properties of items
    in a layout, since this would conflict with the goal of the Layout, and also cause binding
    loops.

    \sa GridLayout
    \sa RowLayout
    \sa ColumnLayout
*/

QT_BEGIN_NAMESPACE

QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
    : QObject(parent),
      m_minimumWidth(0),
      m_minimumHeight(0),
      m_preferredWidth(-1),
      m_preferredHeight(-1),
      m_maximumWidth(std::numeric_limits<qreal>::infinity()),
      m_maximumHeight(std::numeric_limits<qreal>::infinity()),
      m_row(-1),
      m_column(-1),
      m_rowSpan(1),
      m_columnSpan(1),
      m_fillWidth(false),
      m_fillHeight(false),
      m_isFillWidthSet(false),
      m_isFillHeightSet(false),
      m_isMinimumWidthSet(false),
      m_isMinimumHeightSet(false),
      m_isMaximumWidthSet(false),
      m_isMaximumHeightSet(false),
      m_changesNotificationEnabled(true),
      m_alignment(0)
{

}

/*!
    \qmlattachedproperty real Layout::minimumWidth

    This property holds the maximum width of an item in a layout.
    The default value is the items implicit minimum width.

    If the item is a layout, the implicit minimum width will be the minimum width the layout can
    have without any of its items shrink beyond their minimum width.
    The implicit minimum width for any other item is \c 0.

    Setting this value to -1 will reset the width back to its implicit minimum width.

    \sa preferredWidth
    \sa maximumWidth
*/
void QQuickLayoutAttached::setMinimumWidth(qreal width)
{
    if (qIsNaN(width))
        return;
    m_isMinimumWidthSet = width >= 0;
    if (m_minimumWidth == width)
        return;

    m_minimumWidth = width;
    invalidateItem();
    emit minimumWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::minimumHeight

    The default value is the items implicit minimum height.

    If the item is a layout, the implicit minimum height will be the minimum height the layout can
    have without any of its items shrink beyond their minimum height.
    The implicit minimum height for any other item is \c 0.

    Setting this value to -1 will reset the height back to its implicit minimum height.

    \sa preferredHeight
    \sa maximumHeight
*/
void QQuickLayoutAttached::setMinimumHeight(qreal height)
{
    if (qIsNaN(height))
        return;
    m_isMinimumHeightSet = height >= 0;
    if (m_minimumHeight == height)
        return;

    m_minimumHeight = height;
    invalidateItem();
    emit minimumHeightChanged();
}

/*!
    \qmlattachedproperty real Layout::preferredWidth

    This property holds the preferred width of an item in a layout.
    If the preferred width is -1 it will be ignored, and the layout
    will use \l{Item::implicitWidth}{implicitWidth} instead.
    The default is \c -1.

    \sa minimumWidth
    \sa maximumWidth
*/
void QQuickLayoutAttached::setPreferredWidth(qreal width)
{
    if (qIsNaN(width) || m_preferredWidth == width)
        return;

    m_preferredWidth = width;
    invalidateItem();
    emit preferredWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::preferredHeight

    This property holds the preferred height of an item in a layout.
    If the preferred height is -1 it will be ignored, and the layout
    will use \l{Item::implicitHeight}{implicitHeight} instead.
    The default is \c -1.

    \sa minimumHeight
    \sa maximumHeight
*/
void QQuickLayoutAttached::setPreferredHeight(qreal height)
{
    if (qIsNaN(height) || m_preferredHeight == height)
        return;

    m_preferredHeight = height;
    invalidateItem();
    emit preferredHeightChanged();
}

/*!
    \qmlattachedproperty real Layout::maximumWidth

    This property holds the maximum width of an item in a layout.
    The default value is the items implicit maximum width.

    If the item is a layout, the implicit maximum width will be the maximum width the layout can
    have without any of its items grow beyond their maximum width.
    The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY.

    Setting this value to -1 will reset the width back to its implicit maximum width.

    \sa minimumWidth
    \sa preferredWidth
*/
void QQuickLayoutAttached::setMaximumWidth(qreal width)
{
    if (qIsNaN(width))
        return;
    m_isMaximumWidthSet = width >= 0;
    if (m_maximumWidth == width)
        return;

    m_maximumWidth = width;
    invalidateItem();
    emit maximumWidthChanged();
}

/*!
    \qmlattachedproperty real Layout::maximumHeight

    The default value is the items implicit maximum height.

    If the item is a layout, the implicit maximum height will be the maximum height the layout can
    have without any of its items grow beyond their maximum height.
    The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY.

    Setting this value to -1 will reset the height back to its implicit maximum height.

    \sa minimumHeight
    \sa preferredHeight
*/
void QQuickLayoutAttached::setMaximumHeight(qreal height)
{
    if (qIsNaN(height))
        return;
    m_isMaximumHeightSet = height >= 0;
    if (m_maximumHeight == height)
        return;

    m_maximumHeight = height;
    invalidateItem();
    emit maximumHeightChanged();
}

void QQuickLayoutAttached::setMinimumImplicitSize(const QSizeF &sz)
{
    bool emitWidthChanged = false;
    bool emitHeightChanged = false;
    if (!m_isMinimumWidthSet && m_minimumWidth != sz.width()) {
        m_minimumWidth = sz.width();
        emitWidthChanged = true;
    }
    if (!m_isMinimumHeightSet && m_minimumHeight != sz.height()) {
        m_minimumHeight = sz.height();
        emitHeightChanged = true;
    }
    // Only invalidate the item once, and make sure we emit signal changed after the call to
    // invalidateItem()
    if (emitWidthChanged || emitHeightChanged) {
        invalidateItem();
        if (emitWidthChanged)
            emit minimumWidthChanged();
        if (emitHeightChanged)
            emit minimumHeightChanged();
    }
}

void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz)
{
    bool emitWidthChanged = false;
    bool emitHeightChanged = false;
    if (!m_isMaximumWidthSet && m_maximumWidth != sz.width()) {
        m_maximumWidth = sz.width();
        emitWidthChanged = true;
    }
    if (!m_isMaximumHeightSet && m_maximumHeight != sz.height()) {
        m_maximumHeight = sz.height();
        emitHeightChanged = true;
    }
    // Only invalidate the item once, and make sure we emit changed signal after the call to
    // invalidateItem()
    if (emitWidthChanged || emitHeightChanged) {
        invalidateItem();
        if (emitWidthChanged)
            emit maximumWidthChanged();
        if (emitHeightChanged)
            emit maximumHeightChanged();
    }
}

/*!
    \qmlattachedproperty bool Layout::fillWidth

    If this property is \c true, the item will be as wide as possible while respecting
    the given constraints. If the property is \c false, the item will have a fixed width
    set to the preferred width.
    The default is \c false, except for layouts themselves, which default to \c true.

    \sa fillHeight
*/
void QQuickLayoutAttached::setFillWidth(bool fill)
{
    m_isFillWidthSet = true;
    if (m_fillWidth != fill) {
        m_fillWidth = fill;
        invalidateItem();
        emit fillWidthChanged();
    }
}

/*!
    \qmlattachedproperty bool Layout::fillHeight

    If this property is \c true, the item will be as tall as possible while respecting
    the given constraints. If the property is \c false, the item will have a fixed height
    set to the preferred height.
    The default is \c false, except for layouts themselves, which default to \c true.

    \sa fillWidth
*/
void QQuickLayoutAttached::setFillHeight(bool fill)
{
    m_isFillHeightSet = true;
    if (m_fillHeight != fill) {
        m_fillHeight = fill;
        invalidateItem();
        emit fillHeightChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::row

    This property allows you to specify the row position of an item in a \l GridLayout.

    If both \l column and this property are not set, it is up to the layout to assign a cell to the item.

    The default value is \c 0.

    \sa column
    \sa rowSpan
*/
void QQuickLayoutAttached::setRow(int row)
{
    if (row >= 0 && row != m_row) {
        m_row = row;
        repopulateLayout();
        emit rowChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::column

    This property allows you to specify the column position of an item in a \l GridLayout.

    If both \l row and this property are not set, it is up to the layout to assign a cell to the item.

    The default value is \c 0.

    \sa row
    \sa columnSpan
*/
void QQuickLayoutAttached::setColumn(int column)
{
    if (column >= 0 && column != m_column) {
        m_column = column;
        repopulateLayout();
        emit columnChanged();
    }
}

/*!
    \qmlattachedproperty Qt.Alignment Layout::alignment

    This property allows you to specify the alignment of an item within the cell(s) it occupies.

    The default value is \c 0, which means it will be \c{Qt.AlignVCenter | Qt.AlignLeft}

    A valid alignment is a combination of the following flags:
    \list
    \li Qt::AlignLeft
    \li Qt::AlignHCenter
    \li Qt::AlignRight
    \li Qt::AlignTop
    \li Qt::AlignVCenter
    \li Qt::AlignBottom
    \li Qt::AlignBaseline
    \endlist

*/
void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
{
    if (align != m_alignment) {
        m_alignment = align;
        if (QQuickLayout *layout = parentLayout()) {
            layout->setAlignment(item(), align);
            invalidateItem();
        }
        emit alignmentChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::rowSpan

    This property allows you to specify the row span of an item in a \l GridLayout.

    The default value is \c 1.

    \sa columnSpan
    \sa row
*/
void QQuickLayoutAttached::setRowSpan(int span)
{
    if (span != m_rowSpan) {
        m_rowSpan = span;
        repopulateLayout();
        emit rowSpanChanged();
    }
}

/*!
    \qmlattachedproperty int Layout::columnSpan

    This property allows you to specify the column span of an item in a \l GridLayout.

    The default value is \c 1.

    \sa rowSpan
    \sa column
*/
void QQuickLayoutAttached::setColumnSpan(int span)
{
    if (span != m_columnSpan) {
        m_columnSpan = span;
        repopulateLayout();
        emit columnSpanChanged();
    }
}

qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const
{
    qreal result = 0;
    if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) {
        const QSizeF sz = layout->sizeHint(which);
        result = (orientation == Qt::Horizontal ? sz.width() : sz.height());
    } else {
        if (which == Qt::MaximumSize)
            result = std::numeric_limits<qreal>::infinity();
    }
    return result;
}

void QQuickLayoutAttached::invalidateItem()
{
    if (!m_changesNotificationEnabled)
        return;
    quickLayoutDebug() << "QQuickLayoutAttached::invalidateItem";
    if (QQuickLayout *layout = parentLayout()) {
        layout->invalidate(item());
    }
}

void QQuickLayoutAttached::repopulateLayout()
{
    if (QQuickLayout *layout = parentLayout())
        layout->updateLayoutItems();
}

QQuickLayout *QQuickLayoutAttached::parentLayout() const
{
    QQuickItem *parentItem = item();
    if (parentItem) {
        parentItem = parentItem->parentItem();
        return qobject_cast<QQuickLayout *>(parentItem);
    } else {
        qWarning("Layout must be attached to Item elements");
    }
    return 0;
}

QQuickItem *QQuickLayoutAttached::item() const
{
    return qobject_cast<QQuickItem *>(parent());
}

QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
    : QQuickItem(dd, parent),
      m_dirty(false)
{
}

QQuickLayout::~QQuickLayout()
{

}

QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
{
    return new QQuickLayoutAttached(object);
}

void QQuickLayout::updatePolish()
{
    rearrange(QSizeF(width(), height()));
}

void QQuickLayout::componentComplete()
{
    QQuickItem::componentComplete();
}

void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
{
    if (m_dirty)
        return;

    m_dirty = true;

    if (!qobject_cast<QQuickLayout *>(parentItem())) {
        quickLayoutDebug() << "QQuickLayout::invalidate(), polish()";
        polish();
    }
}

void QQuickLayout::rearrange(const QSizeF &/*size*/)
{
    m_dirty = false;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/*
Copyright (c) 2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "oslops.h"
#include "oslexec_pvt.h"

#ifdef OSL_NAMESPACE
namespace OSL_NAMESPACE {
#endif
namespace OSL {
namespace pvt {

/////////////////////////////////////////////////////////////////////////
// Notes on how messages work:
//
// The messages are stored in a ParamValueList in the ShadingContext.
// For simple types, just slurp them up into the PVL.
//
// Closures are tricky because of the memory management and that PVL's
// don't know anything about them. For those we allocate new closures
// in the context's closure_msgs vector, and just store their indices in
// the PVL.
//
// FIXME -- setmessage only stores message values, not derivs, so
// getmessage only retrieves the values and has zero derivs.
// We should come back and fix this later.
//
// FIXME -- I believe that if you try to set a message that is an array
// of closures, it will only store the first element.  Also something to
// come back to, not an emergency at the moment.
//
// FIXME -- because we store closures by int index, there's an error
// condition if a shader does a setmessage with a closure, then does a
// getmessage of the same message name into int, or vice versa.  Instead
// that should be a type mismatch and getmessage() should return 0.

// void setmessage (string name, ANY value).
DECLOP (OP_setmessage)
{
    ASSERT (nargs == 2);
    Symbol &Name (exec->sym (args[0]));
    Symbol &Val (exec->sym (args[1]));
    ASSERT (Name.typespec().is_string());

    VaryingRef<ustring> name ((ustring *)Name.data(), Name.step());
    ParamValueList &messages (exec->context()->messages());
    std::vector<ClosureColor> &closure_msgs (exec->context()->closure_msgs());

    bool varying = (Name.is_varying() || Val.is_varying() ||
                    ! exec->all_points_on());
    TypeDesc type = Val.typespec().simpletype();
    if (Val.typespec().is_closure ())
        type = TypeDesc::TypeInt;     // Actually store closure indices only
    size_t datasize = type.size();

    ustring lastname;       // Last message name that we matched
    ParamValue *p = NULL;   // Pointer to the PV for the message

    for (int i = beginpoint;  i < endpoint;  ++i) {
        if (runflags[i]) {
            if (i == beginpoint || name[i] != lastname) {
                // Different message than last time -- search anew
                p = NULL;
                for (size_t m = 0;  m < messages.size() && !p;  ++m)
                    if (messages[m].name() == name[i] &&
                          messages[m].type() == type)
                        p = &messages[m];
                // If the message doesn't already exist, create it
                if (! p) {
                    p = & messages.grow ();
                    p->init (name[i], type,
                             varying ? exec->npoints() : 1, NULL);
                }
                lastname = name[i];
            }

            // Copy the data
            DASSERT (p != NULL);
            char *msgdata = (char *)p->data() + varying*datasize*i;
            if (Val.typespec().is_closure()) {
                // Add the closure data to the end of the closure messages
                closure_msgs.push_back (**(ClosureColor **)Val.data(i));
                // and store its index in the PVL
                *(int *)msgdata = (int)closure_msgs.size() - 1;
            } else {
                // Non-closure types, just memcpy
                memcpy (msgdata, Val.data(i), datasize);
            }
        }
        if (! varying)
            break;      // Non-uniform case can take early out
    }
}

// int getmessage (string name, ANY value)
DECLOP (OP_getmessage)
{
    ASSERT (nargs == 3);
    Symbol &Result (exec->sym (args[0]));
    Symbol &Name (exec->sym (args[1]));
    Symbol &Val (exec->sym (args[2]));
    ASSERT (Result.typespec().is_int() && Name.typespec().is_string());

    bool varying = (Name.is_varying());
    exec->adjust_varying (Result, varying);
    exec->adjust_varying (Val, varying);
    varying |= Result.is_varying();  // adjust in case we're in a conditional

    VaryingRef<int> result ((int *)Result.data(), Result.step());
    VaryingRef<ustring> name ((ustring *)Name.data(), Name.step());
    ParamValueList &messages (exec->context()->messages());
    std::vector<ClosureColor> &closure_msgs (exec->context()->closure_msgs());

    TypeDesc type = Val.typespec().simpletype();
    if (Val.typespec().is_closure ())
        type = TypeDesc::TypeInt;     // Actually store closure indices only
    size_t datasize = type.size();

    ustring lastname;       // Last message name that we matched
    ParamValue *p = NULL;   // Pointer to the PV for the message

    for (int i = beginpoint;  i < endpoint;  ++i) {
        if (runflags[i]) {
            if (i == beginpoint || name[i] != lastname) {
                // Different message than last time -- search anew
                p = NULL;
                for (size_t m = 0;  m < messages.size() && !p;  ++m)
                    if (messages[m].name() == name[i] &&
                          messages[m].type() == type)
                        p = &messages[m];
                if (p && (! varying || Val.is_uniform()) && p->nvalues() > 1) {
                    // all the parameters to the function were uniform,
                    // but the message itself is varying, so adjust Val.
                    exec->adjust_varying (Val, true);
                    varying = true;
                }
                lastname = name[i];
            }

            if (p) {
                result[i] = 1;   // found
                char *msgdata = (char *)p->data() + varying*datasize*i;
                if (Val.typespec().is_closure()) {
                    // Retrieve the closure index from the PVL
                    int index = *(int *)msgdata;
                    ClosureColor *valclose = *(ClosureColor **) Val.data(i);
                    // then copy the closure (or clear it, if out of range)
                    if (index < (int)closure_msgs.size())
                        *valclose = closure_msgs.back();
                    else
                        valclose->clear ();
                } else {
                    memcpy (Val.data(i), msgdata, datasize);
                }
            } else {
                result[i] = 0;   // not found
            }
        }
        if (! varying)
            break;      // Non-uniform case can take early out
    }

    if (Val.has_derivs ())
        exec->zero_derivs (Val);
}

}; // namespace pvt
}; // namespace OSL
#ifdef OSL_NAMESPACE
}; // end namespace OSL_NAMESPACE
#endif
<commit_msg>Fixed a bad reference to closure messages<commit_after>/*
Copyright (c) 2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "oslops.h"
#include "oslexec_pvt.h"

#ifdef OSL_NAMESPACE
namespace OSL_NAMESPACE {
#endif
namespace OSL {
namespace pvt {

/////////////////////////////////////////////////////////////////////////
// Notes on how messages work:
//
// The messages are stored in a ParamValueList in the ShadingContext.
// For simple types, just slurp them up into the PVL.
//
// Closures are tricky because of the memory management and that PVL's
// don't know anything about them. For those we allocate new closures
// in the context's closure_msgs vector, and just store their indices in
// the PVL.
//
// FIXME -- setmessage only stores message values, not derivs, so
// getmessage only retrieves the values and has zero derivs.
// We should come back and fix this later.
//
// FIXME -- I believe that if you try to set a message that is an array
// of closures, it will only store the first element.  Also something to
// come back to, not an emergency at the moment.
//
// FIXME -- because we store closures by int index, there's an error
// condition if a shader does a setmessage with a closure, then does a
// getmessage of the same message name into int, or vice versa.  Instead
// that should be a type mismatch and getmessage() should return 0.

// void setmessage (string name, ANY value).
DECLOP (OP_setmessage)
{
    ASSERT (nargs == 2);
    Symbol &Name (exec->sym (args[0]));
    Symbol &Val (exec->sym (args[1]));
    ASSERT (Name.typespec().is_string());

    VaryingRef<ustring> name ((ustring *)Name.data(), Name.step());
    ParamValueList &messages (exec->context()->messages());
    std::vector<ClosureColor> &closure_msgs (exec->context()->closure_msgs());

    bool varying = (Name.is_varying() || Val.is_varying() ||
                    ! exec->all_points_on());
    TypeDesc type = Val.typespec().simpletype();
    if (Val.typespec().is_closure ())
        type = TypeDesc::TypeInt;     // Actually store closure indices only
    size_t datasize = type.size();

    ustring lastname;       // Last message name that we matched
    ParamValue *p = NULL;   // Pointer to the PV for the message

    for (int i = beginpoint;  i < endpoint;  ++i) {
        if (runflags[i]) {
            if (i == beginpoint || name[i] != lastname) {
                // Different message than last time -- search anew
                p = NULL;
                for (size_t m = 0;  m < messages.size() && !p;  ++m)
                    if (messages[m].name() == name[i] &&
                          messages[m].type() == type)
                        p = &messages[m];
                // If the message doesn't already exist, create it
                if (! p) {
                    p = & messages.grow ();
                    p->init (name[i], type,
                             varying ? exec->npoints() : 1, NULL);
                }
                lastname = name[i];
            }

            // Copy the data
            DASSERT (p != NULL);
            char *msgdata = (char *)p->data() + varying*datasize*i;
            if (Val.typespec().is_closure()) {
                // Add the closure data to the end of the closure messages
                closure_msgs.push_back (**(ClosureColor **)Val.data(i));
                // and store its index in the PVL
                *(int *)msgdata = (int)closure_msgs.size() - 1;
            } else {
                // Non-closure types, just memcpy
                memcpy (msgdata, Val.data(i), datasize);
            }
        }
        if (! varying)
            break;      // Non-uniform case can take early out
    }
}

// int getmessage (string name, ANY value)
DECLOP (OP_getmessage)
{
    ASSERT (nargs == 3);
    Symbol &Result (exec->sym (args[0]));
    Symbol &Name (exec->sym (args[1]));
    Symbol &Val (exec->sym (args[2]));
    ASSERT (Result.typespec().is_int() && Name.typespec().is_string());

    bool varying = (Name.is_varying());
    exec->adjust_varying (Result, varying);
    exec->adjust_varying (Val, varying);
    varying |= Result.is_varying();  // adjust in case we're in a conditional

    VaryingRef<int> result ((int *)Result.data(), Result.step());
    VaryingRef<ustring> name ((ustring *)Name.data(), Name.step());
    ParamValueList &messages (exec->context()->messages());
    std::vector<ClosureColor> &closure_msgs (exec->context()->closure_msgs());

    TypeDesc type = Val.typespec().simpletype();
    if (Val.typespec().is_closure ())
        type = TypeDesc::TypeInt;     // Actually store closure indices only
    size_t datasize = type.size();

    ustring lastname;       // Last message name that we matched
    ParamValue *p = NULL;   // Pointer to the PV for the message

    for (int i = beginpoint;  i < endpoint;  ++i) {
        if (runflags[i]) {
            if (i == beginpoint || name[i] != lastname) {
                // Different message than last time -- search anew
                p = NULL;
                for (size_t m = 0;  m < messages.size() && !p;  ++m)
                    if (messages[m].name() == name[i] &&
                          messages[m].type() == type)
                        p = &messages[m];
                if (p && (! varying || Val.is_uniform()) && p->nvalues() > 1) {
                    // all the parameters to the function were uniform,
                    // but the message itself is varying, so adjust Val.
                    exec->adjust_varying (Val, true);
                    varying = true;
                }
                lastname = name[i];
            }

            if (p) {
                result[i] = 1;   // found
                char *msgdata = (char *)p->data() + varying*datasize*i;
                if (Val.typespec().is_closure()) {
                    // Retrieve the closure index from the PVL
                    int index = *(int *)msgdata;
                    ClosureColor *valclose = *(ClosureColor **) Val.data(i);
                    // then copy the closure (or clear it, if out of range)
                    if (index < (int)closure_msgs.size())
                        *valclose = closure_msgs[index];
                    else
                        valclose->clear ();
                } else {
                    memcpy (Val.data(i), msgdata, datasize);
                }
            } else {
                result[i] = 0;   // not found
            }
        }
        if (! varying)
            break;      // Non-uniform case can take early out
    }

    if (Val.has_derivs ())
        exec->zero_derivs (Val);
}

}; // namespace pvt
}; // namespace OSL
#ifdef OSL_NAMESPACE
}; // end namespace OSL_NAMESPACE
#endif
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "stdafx.h"

#include <atltime.h>
#include "ext/rho/rhoruby.h"
#include "../MainWindow.h"
#include "Camera.h"
#include "common/RhodesApp.h"

#ifdef _MSC_VER
// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
#pragma warning ( disable : 4800 )
#endif

extern "C" HWND getMainWnd();

//#if defined(_WIN32_WCE)

static bool copy_file(LPTSTR from, LPTSTR to);
static LPTSTR get_file_name(LPTSTR from, LPTSTR to);
static LPTSTR generate_filename(LPTSTR filename, LPCTSTR szExt );
static void create_folder(LPTSTR Path);

IMPLEMENT_LOGCLASS(Camera,"Camera");

Camera::Camera(void) {
}

Camera::~Camera(void) {
}

HRESULT Camera::takePicture(HWND hwndOwner,LPTSTR pszFilename)
{
    HRESULT         hResult = S_OK;
#if defined(_WIN32_WCE) && !defined( OS_PLATFORM_MOTCE )
    SHCAMERACAPTURE shcc;

    StringW root;
    convertToStringW(rho_rhodesapp_getblobsdirpath(), root);
    wsprintf( pszFilename, L"%s", root.c_str() );

	create_folder(pszFilename);

    //LPCTSTR szExt = wcsrchr(pszFilename, '.');
    TCHAR filename[256];
	generate_filename(filename,L".jpg");

    // Set the SHCAMERACAPTURE structure.
    ZeroMemory(&shcc, sizeof(shcc));
    shcc.cbSize             = sizeof(shcc);
    shcc.hwndOwner          = hwndOwner;
    shcc.pszInitialDir      = pszFilename;
    shcc.pszDefaultFileName = filename;
    shcc.pszTitle           = TEXT("Camera");
    shcc.VideoTypes			= CAMERACAPTURE_VIDEOTYPE_MESSAGING;
    shcc.nResolutionWidth   = 176;
    shcc.nResolutionHeight  = 144;
    shcc.nVideoTimeLimit    = 15;
    shcc.Mode               = CAMERACAPTURE_MODE_STILL;

    // Display the Camera Capture dialog.
    hResult = SHCameraCapture(&shcc);

    // The next statements will execute only after the user takes
    // a picture or video, or closes the Camera Capture dialog.
    if (S_OK == hResult) {
        LPTSTR fname = get_file_name(shcc.szFile,pszFilename);
		if (fname) {
			StringCchCopy(pszFilename, MAX_PATH, fname);
			free(fname);
		} else {
            LOG(ERROR) + "takePicture error get file: " + shcc.szFile;

			hResult = E_INVALIDARG;
		}
    }else
    {
        LOG(ERROR) + "takePicture failed with code: " + LOGFMT("0x%X") + hResult;
    }
#endif //_WIN32_WCE

    return hResult;
}

HRESULT Camera::selectPicture(HWND hwndOwner,LPTSTR pszFilename)
{
	RHO_ASSERT(pszFilename);
#if defined( _WIN32_WCE ) && !defined( OS_PLATFORM_MOTCE )
	OPENFILENAMEEX ofn = {0};
#else
    OPENFILENAME ofn = {0};
#endif
    pszFilename[0] = 0;

	ofn.lStructSize     = sizeof(ofn);
	ofn.lpstrFilter     = NULL;
	ofn.lpstrFile       = pszFilename;
	ofn.nMaxFile        = MAX_PATH;
	ofn.lpstrInitialDir = NULL;
	ofn.lpstrTitle      = _T("Select an image");
#if defined( _WIN32_WCE ) && !defined( OS_PLATFORM_MOTCE )
	ofn.ExFlags         = OFN_EXFLAG_THUMBNAILVIEW|OFN_EXFLAG_NOFILECREATE|OFN_EXFLAG_LOCKDIRECTORY;
    if (GetOpenFileNameEx(&ofn))
#else
    if (GetOpenFileName(&ofn))
#endif

    {
		HRESULT hResult = S_OK;

        /*
		TCHAR rhoroot[MAX_PATH];
		wchar_t* root  = wce_mbtowc(rho_rhodesapp_getblobsdirpath());
		wsprintf(rhoroot,L"%s",root);
		free(root);

		create_folder(rhoroot);*/

        StringW strBlobRoot = convertToStringW( RHODESAPP().getBlobsDirPath() );

        LPCTSTR szExt = wcsrchr(pszFilename, '.');
		TCHAR filename[256];
		generate_filename(filename, szExt);

		int len = strBlobRoot.length() + wcslen(L"\\") + wcslen(filename);
		wchar_t* full_name = (wchar_t*) malloc((len+2)*sizeof(wchar_t));
		wsprintf(full_name,L"%s\\%s",strBlobRoot.c_str(),filename);

		if (copy_file(pszFilename,full_name))
        {
			wcscpy( pszFilename, filename );
		} else {
			hResult = E_INVALIDARG;
		}

		free(full_name);

		return hResult;
	} else if (GetLastError()==ERROR_SUCCESS) {
		return S_FALSE; //user cancel op
	}
	return E_INVALIDARG;
}

bool copy_file(LPTSTR from, LPTSTR to)
{
	RHO_ASSERT(from);
	RHO_ASSERT(to);
/*
	SHFILEOPSTRUCT SHFileOp;
	ATL::CString source(from);
	ATL::CString destination(to);

	// add required string terminators
	source+=_T("\0\0");
	destination+=_T("\0\0");

	// set up File Operation structure
	ZeroMemory(&SHFileOp, sizeof(SHFILEOPSTRUCT));
	SHFileOp.hwnd = NULL;
	SHFileOp.wFunc = FO_COPY;
	SHFileOp.pFrom = source;
	SHFileOp.pTo = destination;
	SHFileOp.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
*/
	//if(SHFileOperation(&SHFileOp) != 0) {
    if ( !CopyFile(from, to, TRUE) )
    {
        DWORD dwErr = GetLastError();
		return false;
	}
	return true;
}

LPTSTR get_file_name(LPTSTR from, LPTSTR to) {
	int len = wcslen(to);
	if (wcsncmp(to,from,len)==0) {
		LPTSTR fname = from+len;
		if ( (wcsncmp(L"\\",fname,1)==0) ||
			 (wcsncmp(L"/",fname,1)==0) ) {
			fname++;
		}
		len = wcslen(fname);
		wchar_t* name = (wchar_t*) malloc(len*sizeof(wchar_t)+1);
		wcscpy(name,fname);
		return name;
	} else {
		return NULL;
	}
}

LPTSTR generate_filename(LPTSTR filename, LPCTSTR szExt) {
	RHO_ASSERT(filename);

	CTime time(CTime::GetCurrentTime());
	tm tl, tg;
	time.GetLocalTm(&tl);
	time.GetGmtTm(&tg);
	int tz = tl.tm_hour-tg.tm_hour; //TBD: fix tz

    wsprintf(filename, L"Image_%02i-%02i-%0004i_%02i.%02i.%02i_%c%03i%s",
		tg.tm_mon, tg.tm_mday, 1900+tg.tm_year, tg.tm_hour, tg.tm_min, tg.tm_sec,
        tz>0?'_':'-',abs(tz),(szExt?szExt:L""));

	return filename;
}

void create_folder(LPTSTR Path)
{
	TCHAR DirName[256];
	LPTSTR p = Path;
	LPTSTR q = DirName;
	while(*p)
	{
		if (('\\' == *p) || ('/' == *p))
		{
			if (':' != *(p-1))
			{
				CreateDirectory(DirName, NULL);
			}
		}
		*q++ = *p++;
		*q = '\0';
	}
	CreateDirectory(DirName, NULL);
}

//#endif //_WIN32_WCE

void choose_picture(char* callback_url, rho_param *options_hash) {
//#if defined(_WIN32_WCE)
	HWND main_wnd = getMainWnd();
	::PostMessage(main_wnd,WM_SELECTPICTURE,0,(LPARAM)strdup(callback_url));
//#endif
}

void take_picture(char* callback_url, rho_param * options_hash) {
	HWND main_wnd = getMainWnd();
	::PostMessage(main_wnd,WM_TAKEPICTURE,0,(LPARAM)strdup(callback_url));
}

VALUE get_camera_info(const char* camera_type) {
     return rho_ruby_get_NIL();
}
<commit_msg>wm: fix choose picture<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "stdafx.h"

#include <atltime.h>
#include "ext/rho/rhoruby.h"
#include "../MainWindow.h"
#include "Camera.h"
#include "common/RhodesApp.h"

#ifdef _MSC_VER
// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
#pragma warning ( disable : 4800 )
#endif

extern "C" HWND getMainWnd();

//#if defined(_WIN32_WCE)

static bool copy_file(LPTSTR from, LPTSTR to);
static LPTSTR get_file_name(LPTSTR from, LPTSTR to);
static LPTSTR generate_filename(LPTSTR filename, LPCTSTR szExt );
static void create_folder(LPTSTR Path);

IMPLEMENT_LOGCLASS(Camera,"Camera");

Camera::Camera(void) {
}

Camera::~Camera(void) {
}

HRESULT Camera::takePicture(HWND hwndOwner,LPTSTR pszFilename)
{
    HRESULT         hResult = S_OK;
#if defined(_WIN32_WCE) && !defined( OS_PLATFORM_MOTCE )
    SHCAMERACAPTURE shcc;

    StringW root;
    convertToStringW(rho_rhodesapp_getblobsdirpath(), root);
    wsprintf( pszFilename, L"%s", root.c_str() );

	create_folder(pszFilename);

    //LPCTSTR szExt = wcsrchr(pszFilename, '.');
    TCHAR filename[256];
	generate_filename(filename,L".jpg");

    // Set the SHCAMERACAPTURE structure.
    ZeroMemory(&shcc, sizeof(shcc));
    shcc.cbSize             = sizeof(shcc);
    shcc.hwndOwner          = hwndOwner;
    shcc.pszInitialDir      = pszFilename;
    shcc.pszDefaultFileName = filename;
    shcc.pszTitle           = TEXT("Camera");
    shcc.VideoTypes			= CAMERACAPTURE_VIDEOTYPE_MESSAGING;
    shcc.nResolutionWidth   = 176;
    shcc.nResolutionHeight  = 144;
    shcc.nVideoTimeLimit    = 15;
    shcc.Mode               = CAMERACAPTURE_MODE_STILL;

    // Display the Camera Capture dialog.
    hResult = SHCameraCapture(&shcc);

    // The next statements will execute only after the user takes
    // a picture or video, or closes the Camera Capture dialog.
    if (S_OK == hResult) {
        LPTSTR fname = get_file_name(shcc.szFile,pszFilename);
		if (fname) {
			StringCchCopy(pszFilename, MAX_PATH, fname);
			free(fname);
		} else {
            LOG(ERROR) + "takePicture error get file: " + shcc.szFile;

			hResult = E_INVALIDARG;
		}
    }else
    {
        LOG(ERROR) + "takePicture failed with code: " + LOGFMT("0x%X") + hResult;
    }
#endif //_WIN32_WCE

    return hResult;
}

HRESULT Camera::selectPicture(HWND hwndOwner,LPTSTR pszFilename)
{
	RHO_ASSERT(pszFilename);
#if defined( _WIN32_WCE ) && !defined( OS_PLATFORM_MOTCE )
	OPENFILENAMEEX ofn = {0};
#else
    OPENFILENAME ofn = {0};
#endif
    pszFilename[0] = 0;

	ofn.lStructSize     = sizeof(ofn);
    ofn.hwndOwner       = hwndOwner;
	ofn.lpstrFilter     = NULL;
	ofn.lpstrFile       = pszFilename;
	ofn.nMaxFile        = MAX_PATH;
	ofn.lpstrInitialDir = NULL;
	ofn.lpstrTitle      = _T("Select an image");
#if defined( _WIN32_WCE ) && !defined( OS_PLATFORM_MOTCE )
	ofn.ExFlags         = OFN_EXFLAG_THUMBNAILVIEW|OFN_EXFLAG_NOFILECREATE|OFN_EXFLAG_LOCKDIRECTORY;
    if (GetOpenFileNameEx(&ofn))
#else
    if (GetOpenFileName(&ofn))
#endif

    {
		HRESULT hResult = S_OK;

        /*
		TCHAR rhoroot[MAX_PATH];
		wchar_t* root  = wce_mbtowc(rho_rhodesapp_getblobsdirpath());
		wsprintf(rhoroot,L"%s",root);
		free(root);

		create_folder(rhoroot);*/

        StringW strBlobRoot = convertToStringW( RHODESAPP().getBlobsDirPath() );

        LPCTSTR szExt = wcsrchr(pszFilename, '.');
		TCHAR filename[256];
		generate_filename(filename, szExt);

		int len = strBlobRoot.length() + wcslen(L"\\") + wcslen(filename);
		wchar_t* full_name = (wchar_t*) malloc((len+2)*sizeof(wchar_t));
		wsprintf(full_name,L"%s\\%s",strBlobRoot.c_str(),filename);

		if (copy_file(pszFilename,full_name))
        {
			wcscpy( pszFilename, filename );
		} else {
			hResult = E_INVALIDARG;
		}

		free(full_name);

		return hResult;
	} else if (GetLastError()==ERROR_SUCCESS) {
		return S_FALSE; //user cancel op
	}
	return E_INVALIDARG;
}

bool copy_file(LPTSTR from, LPTSTR to)
{
	RHO_ASSERT(from);
	RHO_ASSERT(to);
/*
	SHFILEOPSTRUCT SHFileOp;
	ATL::CString source(from);
	ATL::CString destination(to);

	// add required string terminators
	source+=_T("\0\0");
	destination+=_T("\0\0");

	// set up File Operation structure
	ZeroMemory(&SHFileOp, sizeof(SHFILEOPSTRUCT));
	SHFileOp.hwnd = NULL;
	SHFileOp.wFunc = FO_COPY;
	SHFileOp.pFrom = source;
	SHFileOp.pTo = destination;
	SHFileOp.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
*/
	//if(SHFileOperation(&SHFileOp) != 0) {
    if ( !CopyFile(from, to, TRUE) )
    {
        DWORD dwErr = GetLastError();
		return false;
	}
	return true;
}

LPTSTR get_file_name(LPTSTR from, LPTSTR to) {
	int len = wcslen(to);
	if (wcsncmp(to,from,len)==0) {
		LPTSTR fname = from+len;
		if ( (wcsncmp(L"\\",fname,1)==0) ||
			 (wcsncmp(L"/",fname,1)==0) ) {
			fname++;
		}
		len = wcslen(fname);
		wchar_t* name = (wchar_t*) malloc(len*sizeof(wchar_t)+1);
		wcscpy(name,fname);
		return name;
	} else {
		return NULL;
	}
}

LPTSTR generate_filename(LPTSTR filename, LPCTSTR szExt) {
	RHO_ASSERT(filename);

	CTime time(CTime::GetCurrentTime());
	tm tl, tg;
	time.GetLocalTm(&tl);
	time.GetGmtTm(&tg);
	int tz = tl.tm_hour-tg.tm_hour; //TBD: fix tz

    wsprintf(filename, L"Image_%02i-%02i-%0004i_%02i.%02i.%02i_%c%03i%s",
		tg.tm_mon, tg.tm_mday, 1900+tg.tm_year, tg.tm_hour, tg.tm_min, tg.tm_sec,
        tz>0?'_':'-',abs(tz),(szExt?szExt:L""));

	return filename;
}

void create_folder(LPTSTR Path)
{
	TCHAR DirName[256];
	LPTSTR p = Path;
	LPTSTR q = DirName;
	while(*p)
	{
		if (('\\' == *p) || ('/' == *p))
		{
			if (':' != *(p-1))
			{
				CreateDirectory(DirName, NULL);
			}
		}
		*q++ = *p++;
		*q = '\0';
	}
	CreateDirectory(DirName, NULL);
}

//#endif //_WIN32_WCE

void choose_picture(char* callback_url, rho_param *options_hash) {
//#if defined(_WIN32_WCE)
	HWND main_wnd = getMainWnd();
	::PostMessage(main_wnd,WM_SELECTPICTURE,0,(LPARAM)strdup(callback_url));
//#endif
}

void take_picture(char* callback_url, rho_param * options_hash) {
	HWND main_wnd = getMainWnd();
	::PostMessage(main_wnd,WM_TAKEPICTURE,0,(LPARAM)strdup(callback_url));
}

VALUE get_camera_info(const char* camera_type) {
     return rho_ruby_get_NIL();
}
<|endoftext|>