форматирование значений input type='number'
От: PM  
Дата: 02.10.12 12:38
Оценка:
Всем привет!

Cразу к сути вопроса — есть поле ввода <input type='number'>, хочется форматировать по разному его значения. Например, показывать число в 16-ричной с/с, или строку "нет" для значения 0.

Я правильно понимаю что мне нужно написать собственный behavior и реализовать функцию on_draw() для отрисовки? Я могу как-то при этом унаследовать стандартный behavior number?
Re: форматирование значений input type='number'
От: c-smile Канада http://terrainformatica.com
Дата: 02.10.12 22:23
Оценка: 14 (1)
Здравствуйте, PM, Вы писали:

PM>Всем привет!


PM>Cразу к сути вопроса — есть поле ввода <input type='number'>, хочется форматировать по разному его значения. Например, показывать число в 16-ричной с/с, или строку "нет" для значения 0.


Редактировние и представление (форматирование) это две разные сущности в том смысле что представление данных в этих двух режимах должно выполняться по разному.

В самом общем случае можно делать так:
<form>
Fancy 16-bit number <input type=text filter="0~9A~F" class="for-edit"><span class=for-view />
</form>
И переключать form в режим отображения и режим редактирования пряча/показывая соотв. элементы. В span class=for-view выводить значение в твоем отформатированном виде.

Про: строку "нет" для значения 0.

Значение 0 это значение 0. Пустая строка это значение нет или undefined.
Если так, то попробуй:
<html>
  <head>
  <style>
    input[type=number]:empty { color:red; }
  </style>
  </head>
<body>
  <input type=number novalue="неопределено" >
</body>
</html>
Re[2]: форматирование значений input type='number'
От: PM  
Дата: 03.10.12 13:08
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Редактировние и представление (форматирование) это две разные сущности в том смысле что представление данных в этих двух режимах должно выполняться по разному.


CS>В самом общем случае можно делать так:

CS><form>
CS> Fancy 16-bit number <input type=text filter="0~9A~F" class="for-edit"><span class=for-view />
CS></form>
CS>И переключать form в режим отображения и режим редактирования пряча/показывая соотв. элементы. В span class=for-view выводить значение в твоем отформатированном виде.

Сейчас так и сделано — рядом с input type='number' лежит span показывающий значение из поля ввода в 16-ричной системе. Но захотелось получить полноценный hexadecimal редактор

CS>Про: строку "нет" для значения 0.


CS>Значение 0 это значение 0. Пустая строка это значение нет или undefined.

CS>Если так, то попробуй:

Я имел ввиду аналог property specialValueText из QAbstractSpinBox
Cпасибо, можно попробовать выкрутиться с novalue, забивая undefined вместо 0 и поставив minvalue = 1.

В результате хотелось бы получить нечто похожее на QSpinBox из Qt, с префиксом, суффиксом и текстом для спец. значения.

Я сегодня попробовал добавить собственный behavior для input type='number', но без особых успехов. Пока вижу выход только в дублировании функциональности и стиля из behavior: number в собственном hexnumber
Re[3]: Пример того как это делается
От: c-smile Канада http://terrainformatica.com
Дата: 04.10.12 03:56
Оценка: 28 (2)
Вот пример для Sciter. Портирование в HTMLayout — на совести вопрошающего.

Три файла:

test.htm , <input type="hex-number"> там это оно.

<html>
  <head>
    <style>
    
      @import url(hex-editor.css);
    
    </style>
    <script type="text/tiscript">
    
    $(button#show).onClick = function()
    {
      var v = $(input#hex).value;
      $(pre).text = String.printf("%d %x",v,v);
    }
    
    </script>
  </head>
<body>
  <input type="hex-number" value="0xAFED" id="hex" />
  <button id="show">Show value</button>
  <pre> </pre>
</body>
</html>


Файл hex-editor.css


input[type="hex-number"]
{
    style-set: "hex-edit";
}

@set hex-edit
  {
    :root
    {
      prototype:HexEditor url(hex-editor.tis); 
      font-rendering-mode:snap-pixel;
      font-family:monospace;
      color:windowtext;
      background-image:url(theme:edit-normal); 
      background-repeat:stretch; 
      padding:system-border-width; 
      width: 6em;
      height: min-intrinsic;
      cursor:default;
      white-space: nowrap;
      text-align:right;
        flow:"1 2" 
             "1 3" ;
        //context-menu:url(res:menu-edit.htm);
    }
    :root:rtl
    {
        flow:"2 1" 
             "3 1";
    }
    
    :root > caption 
    { 
      display:block;
      flow:text;
      behavior: edit;      
      height:*; width:*;
      padding:2px; 
      cursor:text;
      white-space:pre;
      overflow-x:hidden-scroll;
      -filter:"0~9A~Fa~f";
      text-selection: windowtext threedface;
    }
    
    :root > caption:focus { 
      text-selection: highlighttext highlight; 
    }
        
    :root:disabled
    { 
      background-image:url(theme:edit-disabled); 
      color:graytext;
    }
  
    :root:invalid
    {
      color:red;
    }
  
    :root > button
    {
      display:block;
      behavior:clickable;
      cursor:default;
      height:0.5*;
      min-height:10dip;
    }
  
    :root > button.minus
    {
      padding:0;
      margin: 0 -2px -2px 0;
      background-image:url(theme:v-spin-minus-normal); 
      background-repeat:stretch; 
      width:system-scrollbar-width;
      height:50%%;
    }
   
    :root > button.minus:hover
    {
      transition:none;
      background-image:url(theme:v-spin-minus-hover); 
    }
    :root > button.minus:active
    {
      background-image:url(theme:v-spin-minus-pressed); 
    }
    :root > button.minus:disabled
    {
      background-image:url(theme:v-spin-minus-disabled); 
    }
    :root > button.plus
    {
      padding:0;
      margin: -2px -2px -1 0;
      background-image:url(theme:v-spin-plus-normal); 
      background-repeat:stretch; 
      width:system-scrollbar-width;
      height:50%%;
    }
    
    :root > button.plus:hover
    {
        transition:none;
      background-image:url(theme:v-spin-plus-hover); 
    }
    :root > button.plus:active
    {
      background-image:url(theme:v-spin-plus-pressed); 
    }
    :root > button.plus:disabled
    {
      background-image:url(theme:v-spin-plus-disabled); 
    }
  
  }


и файл hex-editor.tis с нашим behavior:


class HexEditor : Behavior {

  function attached() {
    // create structure:
    this.caption = new Element("caption"); this.append(this.caption);
    this.inc = new Element("button"); this.inc.attributes["class"] = "plus"; this.append(this.inc);
    this.dec = new Element("button"); this.dec.attributes["class"] = "minus"; this.append(this.dec);
    
    var initialVal = this.attributes["value"];    
    if( initialVal ) this.value = initialVal.toInteger();
  }
  
  property value(v)  
  {
    get { 
      var va = (this.caption.value || "").scanf("%x")
      return typeof va == #array && va.length == 1 ? va[0]: undefined; 
    }
    set { 
      this.caption.value = String.printf("%X",v); 
    }
  }
  
  function onControlEvent(evt)
  {
    if( evt.type == Event.BUTTON_CLICK && evt.target == this.inc )
      this.doInc();
    else if( evt.type == Event.BUTTON_CLICK && evt.target == this.dec )
      this.doDec();
  }
  
  function onMouse(evt)
  {
    if( evt.type == Event.MOUSE_WHEEL )
    {
      if( evt.wheelDelta < 0 ) this.doDec(); else this.doInc();
    }
  }
  
  function doInc()
  {
    var v = this.value;
    if( typeof v == #integer ) this.value += 1;
    else this.value = 0;
  }
  function doDec()
  {
    var v = this.value;
    if( typeof v == #integer ) this.value -= 1;
    else this.value = 0xFFFF;
  }
}
Re[4]: Пример того как это делается
От: PM  
Дата: 04.10.12 13:27
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Вот пример для Sciter. Портирование в HTMLayout — на совести вопрошающего.


Спасибо! попробую сделать это в HTMLayout
Re[5]: Пример того как это делается
От: PM  
Дата: 30.10.12 05:49
Оценка: 56 (2)
Здравствуйте, PM, Вы писали:

PM>Здравствуйте, c-smile, Вы писали:


CS>>Вот пример для Sciter. Портирование в HTMLayout — на совести вопрошающего.


Вот, портировал, вдруг кому еще пригодится. Спасибо c-smile, все оказалось не так страшно

#include "behavior_aux.h"

namespace htmlayout {

/** behavior:hexnumber, hexadecimal number edit.
 *  Behaves like number, size attribute defines width of value
 *
 *  <input type="hex-number" size="4" step="1 minvalue="0" maxvalue="65535" />
 *
 **/

class hexnumber : public behavior
{
public:
    hexnumber()
        : behavior(HANDLE_MOUSE | HANDLE_KEY | HANDLE_BEHAVIOR_EVENT | HANDLE_METHOD_CALL, "hexnumber")
    {
        char const css[] = " input[type=\"hex-number\"] { style-set: \"hex-edit\"; }"
            "@set hex-edit {"
            "    :root {"
            "      behavior:hexnumber;"
            "      font-rendering-mode:snap-pixel; font-family:monospace;"
            "      background-image:url(theme:edit-normal); background-repeat:stretch; "
            "      padding:system-border-width; width: 6em; height: min-intrinsic;"
            "      color:windowtext; cursor:text; white-space: nowrap; text-align:right;"
            "      flow:\"1 2\""
            "           \"1 3\"; }"
            "    :root:rtl {"
            "        flow:\"2 1\""
            "             \"3 1\"; }"
            "    :root > caption {"
            "      display:block; flow:text; behavior: edit; size:*; padding:2px; cursor:text;"
            "      white-space:pre; overflow-x:hidden-scroll; -filter:\"0~9A~Fa~f\";"
            "      text-selection: windowtext threedface; }"
            "    :root > caption:focus { text-selection: highlighttext highlight; }"
            "    :root:disabled { background-image:url(theme:edit-disabled); color:graytext; }"
            "    :root:invalid { color:red; }"
            "    :root > button { display:block; padding:0; behavior:clickable; cursor:default; height:0.5*; min-height:10dip; }"
            "    :root > button.minus { margin: 0 -2px -2px 0;"
            "      background-image:url(theme:v-spin-minus-normal);  background-repeat:stretch; width:system-scrollbar-width; }"
            "    :root > button.minus:hover { transition:none; background-image:url(theme:v-spin-minus-hover); }"
            "    :root > button.minus:active { background-image:url(theme:v-spin-minus-pressed); }"
            "    :root > button.minus:disabled { background-image:url(theme:v-spin-minus-disabled); }"
            "    :root > button.plus { margin: -2px -2px -1 0;"
            "      background-image:url(theme:v-spin-plus-normal); background-repeat:stretch; width:system-scrollbar-width; }"
            "    :root > button.plus:hover { transition:none; background-image:url(theme:v-spin-plus-hover); }"
            "    :root > button.plus:active { background-image:url(theme:v-spin-plus-pressed); }"
            "    :root > button.plus:disabled { background-image:url(theme:v-spin-plus-disabled); }"
            "}";

        ::HTMLayoutAppendMasterCSS((LPCBYTE)css, sizeof(css));
    }

private:
// behavior implementation

    virtual void attached(HELEMENT he)
    {
        dom::element self = he;

        dom::element caption = dom::element::create("caption");
        self.append(caption);

        if ( step(self) )
        {
            dom::element inc = dom::element::create("button");
            inc.set_attribute("class", L"plus");
            self.append(inc);

            dom::element dec = dom::element::create("button");
            dec.set_attribute("class", L"minus");
            self.append(dec);
        }

        int const val = self.get_attribute_int("value", -1);
        if ( val >= 0 )
        {
            set_value(self, val);
        }
    }

    virtual BOOL handle_event(HELEMENT he, BEHAVIOR_EVENT_PARAMS& params)
    {
        if ( params.cmd == BUTTON_CLICK )
        {
            if ( params.heTarget == inc(he) )
            {
                do_inc(he);
                return true;
            }
            else if ( params.heTarget == dec(he) )
            {
                do_dec(he);
                return true;
            }
        }
        return false;
    }

    virtual BOOL handle_mouse(HELEMENT he, MOUSE_PARAMS& params)
    {
        if ( params.cmd == MOUSE_WHEEL )
        {
            int const wheel_delta = params.button_state;
            if ( wheel_delta < 0 && dec(he) )
            {
                do_dec(he);
                return true;
            }
            else if ( wheel_delta > 0 && inc(he) )
            {
                do_inc(he);
                return true;
            }
        }
        return false;
    }

    virtual BOOL handle_key(HELEMENT he, KEY_PARAMS& params)
    {
        if ( params.cmd == KEY_DOWN )
        {
            if ( params.key_code  == VK_UP && inc(he) )
            {
                do_inc(he);
                return true;
            }
            else if ( params.key_code == VK_DOWN && dec(he) )
            {
                do_dec(he);
                return true;
            }
        }
        return false;
    }

    virtual BOOL handle_method_call(HELEMENT he, METHOD_PARAMS& params)
    {
        if ( params.methodID == GET_VALUE )
        {
            static_cast<VALUE_PARAMS&>(params).val = get_value(he);
            return true;
        }
        else if ( params.methodID == SET_VALUE )
        {
            set_value(he, static_cast<VALUE_PARAMS&>(params).val);
            return true;
        }
        return false;
    }

private:
    static void set_value(dom::element self, json::value val)
    {
        dom::element caption = self.find_first("caption");
        if ( caption )
        {
            if ( val.is_int() )
            {
                int const width = max(self.get_attribute_int("size", 1), 1);
                std::vector<wchar_t> buf(width + std::numeric_limits<unsigned>::digits / 4 + 1);
                swprintf(&buf[0], buf.size(), L"%.*X", width, val.get(0));
                val = &buf[0];
            }
            caption.set_value(val);
        }
    }

    static json::value get_value(dom::element self)
    {
        json::value result;

        dom::element caption = self.find_first("caption");
        if ( caption )
        {
            int val = 0;
            json::string const str = caption.get_value().get(L"");
            if ( swscanf(str.c_str(), L"%x", &val) == 1 )
            {
                val = max(min_value(self), min(val, max_value(self)));
                result = val;
            }
        }
        return result;
    }

    static int step(dom::element self)
    {
        return self.get_attribute_int("step", 0);
    }

    static int min_value(dom::element self)
    {
        return self.get_attribute_int("minvalue", 0);
    }

    static int max_value(dom::element self)
    {
        return self.get_attribute_int("maxvalue", 0xFFFF);
    }

    static dom::element inc(dom::element self)
    {
        return self.find_first("button[class='plus']");
    }

    static dom::element dec(dom::element self)
    {
        return self.find_first("button[class='minus']");
    }

    static void do_inc(dom::element self)
    {
        json::value val = get_value(self);
        val = val.is_int()? min(val.get(0) + step(self), max_value(self)) : min_value(self);
        set_value(self, val);
    }

    static void do_dec(dom::element self)
    {
        json::value val = get_value(self);
        val = val.is_int()? max(val.get(0) - step(self), min_value(self)) : max_value(self);
        set_value(self, val);
    }
};

// instantiating and attaching it to the global list
hexnumber hexnumber_instance;

} // htmlayout namespace
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.