libGUI

Discussing libraries simplifying applications development
  • Leency
    Ну, в общем, то я и сам так представлял внешний вид. :-)
    И даже сделать такое не сложно, но вот как обмениваться с приложениями?... Пока не представляю.
  • erema wrote:Вот только если кто-то "выкинет" GUI...
    По идее должен получить ошибку от ядра (или чего у вас там). Главное, чтобы вразумительную. Типа, "Уважаемый пользователь, вы выкинули GUI и стали сами себе дураком".
  • Замечания по libGUI.
    1. Что за странная модель передачи входных и выходных значений? Если это предназначено для ассемблерщиков, то проще всё передавать в регистрах, если рассматривается вариант для ЯВУ - то есть нормальная модель stdcall, когда входные параметры передаются в стеке, а возвращаемое значение в eax (а не заталкивается зачем-то в стек).
    2. Пример editbox: запускаем, щёлкаем мышкой по полю ввода, нажимаем Backspace (в пустом поле ввода). Фокус ввода исчезает. Снова щёлкаем мышкой по полю ввода и нажимаем Backspace. Программа вылетает.
    3. Почему нет средств программного управления фокусом ввода? Что ли, симулировать нажатия мышкой при необходимости?
    4. Раз уж различные версии несовместимы, где средства контроля версий (как в библиотеках console и libini)?
    5. Что за странные экспортируемые имена? "craete editbox" - заменить на "create_editbox" или "CreateEditBox" - по вкусу.
    Ушёл к умным, знающим и культурным людям.
  • 1) Как передавать параметры - обсуждалось в этой теме.Обсуждение было открытым. В результате обсуждения пришли к выводу, что параметры нужно передавать через стек.Конкретных вариантов НЕБЫЛО вообще. Я подумал как это можно сделать и реализовал в первой версии свой вариант передачи параметров. НИКТО НЕ ВЫСКАЗАЛСЯ НИ ЗА НИ ПРОТИВ этого варианта. И я стал использовать его дальше. Проверкой исходников занимаются в основном только авторы.

    2)То, что editbox не работает, я писал. Я не автор этого компонента, я только пытался адаптировать его для библиотеки. Но так, как автору в это время было совершенно некогда заниматься этим компонентом, то один баг так и остался неисправленным.

    3) В смысле чтобы некоторые компоненты(EditBox например ) автоматически активировались ? В принципе можно посылать свои координаты мыши, чтобы активировать компонент. А если делать автоматическую активацию, то надо добавлять новую функцию в библиотеку. Как её можно назвать ?

    4)Когда будет время - добавлю. Я что-то не придавал внимания этому.

    5)Какая разница, как называются имена, ведь главное получить указатель на начало функции, чтобы её вызвать ? В программе эти функции можно назвать по любому(желательно придерживаться одинаковых названий для разных программ разных авторов).
  • andrew_programmer wrote:В программе эти функции можно назвать по любому(желательно придерживаться одинаковых названий для разных программ разных авторов).
    Вот именно потому, что в программе их можно назвать по-любому, и нужны эталонные названия - на горизонте маячит Kolibri SDK для языков высокого уровня.
  • andrew_programmer
    1. Конвенция вызова stdcall: входные параметры передаются в стеке (так, что на вершине стека оказывается первый из параметров), возвращаемое значение - в регистре eax (64-битное целое - в паре edx:eax), стек очищает вызываемая функция. Примерно так:

    Code: Select all

    ; главная программа
    ...
    push param4
    push param3
    push param2
    push param1
    call [Function]
    mov [returnValue], eax
    ...
    

    Code: Select all

    ; библиотека
    Function:
    mov eax, [esp+4] ; первый параметр
    mov ecx, [esp+8] ; второй параметр
    ...
    mov eax, returnValue
    ret 4*4 ; выталкиваем 4 параметра
    
    При использовании macros.inc:

    Code: Select all

    ; главная программа
    invoke Function, param1,param2,param3,param4
    mov [returnValue],eax
    

    Code: Select all

    ; библиотека
    proc Function stdcall, param1:dword, param2:dword, param3:dword, param4:dword
    mov eax,[param1] ; первый параметр
    ...
    mov eax,returnValue
    ret
    endp
    
    Во втором случае параметры адресуются неявно через ebp, так что сама процедура не может использовать ebp.
    Кстати, конвенция stdcall предписывает сохранять регистры ebx,esi,edi,ebp.
    2. В приложениях, использующих editbox напрямую (run, kfm, rdsave), этого глюка нет.
    3. В том то и дело, что неудобно рассчитывать координаты мыши, которые надо передавать, а также при таком подходе нужно два вызова функции - первый эмулирует нажатие, второй - отжатие.
    5. Я смотрел используемую концепцию импорта. Она, конечно, работает, но идеологически неправильна. Дело в следующем. Формат таблицы экспорта на псевдо-Си:

    Code: Select all

    typedef struct
    {
    const char* FuncName;
    const void* FuncAddr;
    } item;
    item EXPORTS[];
    
    Вариант импорта в libGUI (условно):

    Code: Select all

    SendMessage = EXPORTS[2].FuncAddr;
    CreateEditBox = EXPORTS[3].FuncAddr;
    
    Вариант импорта, изначально предлагаемый автором подхода Serge и реализованный везде, кроме libGUI:

    Code: Select all

    for (i пробегает таблицу импорта)
      if (!strcmp(EXPORTS[i].FuncName,"SendMessage"))
      {SendMessage = EXPORTS[i].FuncAddr;break;}
    
    Подход libGUI работает, но только до тех пор, пока 2-й вход в таблице экспорта соответствует SendMessage. А что, если нужно добавить новую функцию? Добавлять её всегда в конец? А если какая-то из существующих функций в новой версии библиотеки не имеет смысла и должна быть удалена? Для справки: в Windows соответствующие подходы именуются импортом по ординалу и импортом по имени, и импорт из системных библиотек типа kernel32 должен осуществляться по имени. В *nix импорта по ординалу нет вообще.
    И вот для импорта по имени нужны осмысленные корректные имена.
    Ушёл к умным, знающим и культурным людям.
  • andrew_programmer

    3. Обычно такая функция называется SetFocus(control). В дополнение к ней пишутся обработчики OnSetFocus() и OnLostFocus() для событий получения и потери фокуса контролами или один общий обработчик OnChangeFocus()
  • diamond

    Спасибо за советы.

    Между обычным EditBox-ом(1) и EditBox-ом(2) встроенным в libGUI есть одно принципиальное
    различие - у них разные методы получения координат мыши.(1) компонент получает координаты
    мыши относительно левого верхнего угла экрана. Потом из процесса узнаются координаты окна, в
    котором нарисован компонент, после берётся разность координат.Эта разность задаёт координаты
    мыши внутри окна. Зачем это делается - мне непонятно. Рисовать за пределами окна непозволит
    система, а координаты мыши внутри окна можно и так узнать.
    В libGUI координаты мыши берутся относительно окна, потом эти координаты посылаются ввиде
    сообщения и библиотека добавляет к координатам высоту скина и ширину боковой рамки.Я пытался
    переделать компонент (1) для работы с координатами мыши рассчитанными относительно окна.
    Переделать удалось, но вместе с переделкой я внёс какую-то ошибку в компонент.Это скорее всего
    связано с ошибкой в работе со стеком.Хотя я потратил немало времени на поиск ошибки, найти
    место,где происходит ошибка, мне неудалось.

    Serge

    Можно, пожалуйста, пример использования этих функций, чтобы я окончательно понял идею :) ?
  • andrew_programmer

    SetFocus(control) назначает контролу фокус ввода т.е. все нажатые клавиши будут посылаться ему. Функция посылает сообщения kill_focus предыдущему контролу и set_focus новому. Это необходимо чтобы они могли отреагировать на изменения фокуса. Например в Win поля ввода прячут или устанавливают курсор ввода (caret) и меняют подсветку выделенного текста. В диалогах кнопки отрисовывают рамку при переборе по Tab и т.д. Возвращаемое значение - хендл предыдущего контрола имевшего фокус.
  • Итак полетели камни в мой огород :)). Объясню почему было сделано получение координат мышки таким странным образом в посленей ревизии EditBox. Дело в том, что есть разные стили оформления окна, при выводе окна нужно учитывать относительно чего считаются координаты, например, в разных программах KFM,Run используется по разному отсчет координат, для унификации и была придумана данная идея получения координат. Вот вырезка и исходного кода:

    Code: Select all

    ;----------------------------------------------------------
    ;--- получаем координаты мыши относительно 0 т.е всей области экрана
    ;----------------------------------------------------------
    @@:     mcall   37,0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;Функция обработки  мышки получение координат и проверка их + выделения
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    use_work_mause scr_h,scr_w
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;Общие функции обработки 
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    use_general_func
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;Функции для работы с key
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    use_key_func
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;Функции для работы с mouse
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    use_mouse_func scr_w
    Итак в самом начале мы получили координаты мышки относительно верхнего левого угла экрана.
    Далее получаем координаты нашего приложения, фунцией 9, от куда узнаем координаты нашего окна, далее вычиляем координаты, с учетом оформления, т.е. при сборке нужно указать ширину и высоту рамок оформления, или же не указывать их совсем. Данный метод, на мой взгляд является универсальным, т.к. он независим в будующем от типа оформления и других факторов.
    В примере EditBox реализован код управления множеством или подгруппой EditBox, при переносе кода EditBox в библиотеку, необходимо переработать идею упраления EditBox. В библиотеке должен быть реализован демон обработки событий, фокуса, и т.д. Задача EditBox заключается в корректной обработке предоставляемых данных, а не самой обрабатывать события и реагировать на них. К тому же реализация для библиотеки должна быть выполнена с передачей в стеке, а не в регистрах, в духе С.

    P.S. Забыл еще добавить, такая сложная обработки координат положения окна необходима для того что бы можно было выделять текст в Editbox, даже если курсор ушел за пределы активного окна приложения.
  • На мой взгляд все сводиться к тому, что необходимо представить стандарт по архитектурной разработке библиотеки. Поправьте меня если я ошибусь.
    Библиотеки можно разделить на два типа - это содержащие менеджер обработки событий т.е. нужно передавать события и обычные, которым нужно передавать данные к примеру в стеке и получать определенный результат.

    1) Код библиотеки должен быть реентерантным.
    2) Все пользовательские данные должны храниться в памяти у пользовательской программы.
    3) Загрузка двух и более копий одной библиотеки не допускается
    4) Предоставление одной копии DLL разным программам через системный драйвер.

    Как все будет выглядеть:
    Итак при первом обращении приложение через драйвер реализует загрузку библиотеки, по некоторому адресу. Если запускается еще одно приложение, и запрашивает ту же библиотеку, то получает
    линки на загруженую библиотеку и может передавать управление на нее. Разработка драйверной модели позволит исключить загрузку лишнего кода, уменьшиться общее кол-во используемой памяти под загрузку библиотеки. Драйвер по сути будет являться менеджером по загрузки, выгрузке, предоставлению сервиса программам, которые будут обращаться к нему. расходы программы сократятся до выделения места только под данные, которые будут храниться в пользовательской программе. Драйверная модель загрузки библиотек нуждается в сервисе разграничения доступа к памяти куда загружены будут библиотеки.

    Еще нужно разработать универсальный обработчик событий для компонентов, с обратной связью. Т.е. предлагаю всем принять участие в обсуждении данных тем.
    Приведу пример. Для корректной обработки мышки у EDITBOX необходимо в определеннный момент предоствавить монопольный доступ к обработки сообщений от мышки. Этот момент выглядит так: при нажатии клавиши мышки и попадании курсора в активную область editbox, необходимо монопольно передавать перемещение мышке боксу т.к. в начале бокс поймал фокус, а затем можно выделить область ввода при помощи перемещения мышки, до тех пор, пока пользователь не отпустит кнопку мышки. Допускаю, что существуют более сложные комбинации для обработки сложных событий, следовательно, Общий обработчик событий должен уметь обрабатывать внешний код, представленный в коде вызывающей программы, т.к. на все случаи жизни не возможно предусмотреть и написать универсальный обработчик. Остановимся на событиях. событие от клавиатуры, события от мышки, события от IPC ...... События клавиатуры предоставляются объекту с фокусом, и он самостоятельно их обрабатывает. События от мышки то же стандартны - предоставление фокуса объекту, и передачу ему координат, пока не будет отжата клавиша.
  • Сделал набросок своей библиотеки, используется компонет editbox, исходники не выкладываю, т.к. сырые, и хочется добавить еще функциональности. Посмотреть пример можно, скачав прикрепленный файл.

    Code: Select all

    ;DATA данные
    ini_file db 'box_lib.obj',0
    myimport:
    edit_box_draw   dd      aEdit_box_draw
    edit_box_key    dd      aEdit_box_key
    edit_box_mouse  dd      aEdit_box_mouse
    version         dd      aVersion
                    dd      0
                    dd      0
    
    aEdit_box_draw  db 'edit_box',0
    aEdit_box_key   db 'edit_box_key',0
    aEdit_box_mouse db 'edit_box_mouse',0
    aVersion        db 'version',0
    Это экспортируемые данные.

    Вот пример вызова функций:

    Code: Select all

    red_win:
        call draw_window            ;первоначально необходимо нарисовать окно
    align 4
    still:                          ;основной обработчик
            mcall   10              ;Ожидать события
            dec  eax
            jz   red_win
            dec  eax
            jz   key
            dec  eax
            jz   button
    
            push    dword edit1
            push    22
            push    5
            call    [edit_box_mouse]
    
    
            jmp still    ;если ничего из перечисленного то снова в цикл
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    button:
            mcall   17      ;получить идентификатор нажатой клавиши
            test ah,ah              ;если в ah 0, то перейти на обработчик событий still
            jz  still
    exit:   mcall   -1
    key:
            mcall   2       ;загрузим значение 2 в регистор eax и получим код нажатой клавиши
    
            push    dword edit1
            call    [edit_box_key]
    
        jmp still
    
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    align 4
    draw_window:            ;рисование окна приложения
            mcall   12,1
            mcall   0,(50*65536+390),(30*65536+200),0xb3AABBCC,0x805080DD,hed
    
            push    dword edit1
            call    [edit_box_draw]
    
            mcall   12,2
        ret
    ;Data
    edit1 edit_box 250,5,30,0xffffff,0x6f9480,0,0xAABBCC,0,308,hed,ed_focus,43,43
    hed db   'EDITBOX load from lib <Lrz> date 20.09.2007',0
    rb  256
    
    

    Обновил файл
    Attachments
    EDITBOX_LIB.7z (18.52 KiB)
    Downloaded 242 times
    Last edited by <Lrz> on Fri Sep 21, 2007 5:59 pm, edited 1 time in total.
  • Не хочет извлекать архив ни раром, ни 7-зипом((((
    Хотя если открыть в Блокноте видно что файл 7зипа. :?
    Из хаоса в космос
  • исходник залит на ftp в папке Lrz
  • Who is online

    Users browsing this forum: No registered users and 30 guests